Produktet blev tilføjet favoritliste Produktet blev fjernet fra din favoritliste
Otto schachner logo
Error executing template "Designs/OttoSchachner/eCom/ProductCatalog/ProductView.cshtml"
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at CompiledRazorTemplates.Dynamic.RazorEngine_da1f2bae7d3c426b90e6dac773a13a1a.ExecuteAsync()
   at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(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.ViewModelTemplate<Dynamicweb.Ecommerce.ProductCatalog.ProductViewModel> 2 @using System.Diagnostics.SymbolStore 3 @using Dynamicweb.Content 4 @using Dynamicweb.Content.Data 5 @using Dynamicweb.Ecommerce 6 @using Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites 7 @using Dynamicweb.Ecommerce.Prices 8 @using Dynamicweb.Frontend 9 @using Dynamicweb.Frontend.Devices 10 @using Dynamicweb.Frontend.Navigation 11 @using Dynamicweb.Ecommerce.ProductCatalog 12 @using Dynamicweb.Ecommerce.Products 13 @using Dynamicweb.Ecommerce.Shops 14 @using Dynamicweb.Ecommerce.Variants 15 @using Dynamicweb.Rendering 16 @using OttoSchachner.CustomCode.Helpers 17 18 @{ 19 var isCsv = string.Equals(Dynamicweb.Context.Current.Request.QueryString["download"], "csv", StringComparison.OrdinalIgnoreCase); 20 if (isCsv) 21 { 22 var fileVirtual = OttoSchachner.CustomCode.Helpers.ProductCsvExport.CreateTempCsvFile( 23 Model.Id, 24 Model.VariantId, 25 Model.LanguageId, 26 Model, 27 Pageview.User 28 ); 29 30 Dynamicweb.Context.Current.Response.Redirect(fileVirtual); 31 return; 32 } 33 34 var isZip = string.Equals(Dynamicweb.Context.Current.Request.QueryString["download"], "imageszip", StringComparison.OrdinalIgnoreCase); 35 if (isZip) 36 { 37 var zipVirtual = OttoSchachner.CustomCode.Helpers.ProductImagesZipExport.CreateTempImagesZipFile( 38 Model.Id, 39 Model.VariantId, 40 Model.LanguageId, 41 Model 42 ); 43 44 Dynamicweb.Context.Current.Response.Redirect(zipVirtual); 45 return; 46 } 47 } 48 49 @{ 50 string RenderPriceMatrix() 51 { 52 Dynamicweb.Ecommerce.Products.ProductService productService = new Dynamicweb.Ecommerce.Products.ProductService(); 53 ProductQuantityPrices matrixProvider = new ProductQuantityPrices(); 54 var productPriceMatrix = matrixProvider.GetProductQuantityPrices(productService.GetProductById(Model.Id, Model.VariantId, Model.LanguageId)); 55 var uniquePrices = productPriceMatrix 56 .GroupBy(p => new { p.Quantity, Unit = Model.ProductFields["VjmSalesUnit"].Value, Amount = Dynamicweb.Core.Converter.ToDouble(p.Amount) }) 57 .Select(g => g.First()) 58 .ToList(); 59 <div class="pview__matrix mb-4"> 60 @if (uniquePrices.Count != 0) 61 { 62 <div class="d-flex flex-row justify-content-between mb-2"> 63 <div class="fw-bold">@Translate("price-matrix-amount", "Antal")</div> 64 <div class="fw-bold">@Translate("price-matrix-price", "Pris")</div> 65 </div> 66 67 68 bool notLast = true; 69 int index = 0; 70 71 72 foreach (var price in uniquePrices) 73 { 74 <div class="d-flex flex-row justify-content-between"> 75 <div>@price.Quantity @price.UnitId</div> 76 <div>@Dynamicweb.Core.Converter.ToDouble(price.Amount).ToString("F2")</div> 77 </div> 78 79 if (index < uniquePrices.Count - 1) 80 { 81 <hr></hr> 82 } 83 84 index++; 85 } 86 } 87 else 88 { 89 <div class="fw-bold"> 90 @Translate("price-matrix-no-prices", "Ingen mængdepriser fundet") 91 </div> 92 } 93 </div> 94 95 return ""; 96 } 97 98 string RenderSections() 99 { 100 <div class="mb-4"> 101 <!-- Specifikationer - skjult for nu --> 102 103 @* <div class="pview__section"> *@ 104 @* <a href="javascript:void(0)" data-id="specifikationer" class="pview__section__name-container d-flex align-items-center justify-content-between"> *@ 105 @* *@ 106 @* <div class="d-flex flex-row"> *@ 107 @* <i class="pview__section__name-container__icon fa-solid fa-gears"></i> *@ 108 @* *@ 109 @* <div class="pview__section__name-container__name"> *@ 110 @* @Translate("product-specifications", "Specifikationer") *@ 111 @* </div> *@ 112 @* </div> *@ 113 @* <i class="bi-chevron-down"></i> *@ 114 @* <i class="bi-chevron-up d-none"></i> *@ 115 @* </a> *@ 116 @* *@ 117 @* <div data-id="specifikationer" class="pview__section__content"> *@ 118 @* Indhold *@ 119 @* </div> *@ 120 @* *@ 121 @* </div> *@ 122 123 @{ 124 var download = Dynamicweb.Core.Converter.ToString(Model.ProductFields.Where(x => x.Key == "VjmDocumentLibraryHtml").FirstOrDefault().Value.Value); 125 bool hasDocDownloads = !string.IsNullOrEmpty(download); 126 127 var current = Dynamicweb.Context.Current.Request.RawUrl ?? ""; 128 var csvUrl = current + (current.Contains("?") ? "&" : "?") + "download=csv"; 129 var zipUrl = (Dynamicweb.Context.Current.Request.RawUrl ?? "/") + 130 ((Dynamicweb.Context.Current.Request.RawUrl ?? "/").Contains("?") ? "&" : "?") + 131 "download=imageszip"; 132 } 133 134 <div class="pview__section"> 135 <a href="javascript:void(0)" data-id="Downloads" class="pview__section__name-container d-flex align-items-center justify-content-between"> 136 <div class="d-flex flex-row"> 137 <i class="pview__section__name-container__icon fa-solid fa-file-pdf"></i> 138 <div class="pview__section__name-container__name"> 139 @(Translate("product-downloads", "Downloads")) 140 </div> 141 </div> 142 <i class="bi-chevron-down"></i> 143 <i class="bi-chevron-up d-none"></i> 144 </a> 145 146 <div data-id="Downloads" class="pview__section__content"> 147 <div class="d-flex flex-column"> 148 <a class="os-button os-button--red mb-2" href="@csvUrl"> 149 @Translate("download-csv", "Download CSV") 150 </a> 151 152 <a class="os-button os-button--red mb-2" href="@zipUrl"> 153 @Translate("download-images-zip", "Download billeder ZIP") 154 </a> 155 156 @if (hasDocDownloads) 157 { 158 @download 159 } 160 </div> 161 </div> 162 </div> 163 </div> 164 165 return ""; 166 } 167 168 bool signedIn = PageView.Current().User != null; 169 bool purchasable = false; 170 171 if (signedIn) 172 { 173 if (Model.VariantCombinations().Count > 1 && string.IsNullOrEmpty(Model.VariantId)) 174 { 175 purchasable = false; 176 } 177 else 178 { 179 purchasable = true; 180 } 181 } 182 183 List<BreadcrumbItem> items = new List<BreadcrumbItem>(); 184 bool isMobile = PageView.Current().Device == DeviceType.Mobile; 185 186 var groupService = new GroupService(); 187 var shop = new ShopService().GetShop("SHOP1"); 188 var groups = groupService.FindPath(shop, groupService.GetGroup(Model.PrimaryOrDefaultGroup.Id)); 189 var shopPageId = GetPageIdByNavigationTag("Shop"); 190 var product = new ProductService().GetProductById(Model.Id, Model.VariantId, Model.LanguageId); 191 var productImageService = new ProductImageService(); 192 var images = productImageService.GetImagesFromPatterns(product, shop).ToList(); 193 bool variantSelected = !string.IsNullOrEmpty(Model.VariantId); 194 var pageService = new PageService(); 195 196 if (variantSelected) 197 { 198 images.Clear(); 199 images.Add(Model.DefaultImage.Value); 200 } 201 202 foreach (var group in groups) 203 { 204 items.Add(new BreadcrumbItem 205 { 206 Title = group.Name, 207 Url = "/Default.aspx?ID=" + shopPageId + "&groupid=" + group.Id 208 }); 209 } 210 211 var parameters = new Dictionary<string, object>(); 212 parameters.Add("items", items); 213 214 var _navigationSettings = new Dynamicweb.Frontend.Navigation.NavigationSettings() 215 { 216 Parameters = parameters 217 }; 218 219 var _navigationTemplate = "../Partials/Breadcrumb.cshtml"; 220 221 var alternativeImageObject = Model.ProductFields.Where(x => x.Key == "VjmpAlternativeManufacturerBrandLogo").FirstOrDefault(); 222 var alternativeImage = Dynamicweb.Core.Converter.ToString(alternativeImageObject.Value.Value); 223 } 224 <div class="pview os-container "> 225 226 <div class="pview__top position-relative d-flex flex-row justify-content-between align-items-center"> 227 228 <div class="pview__top__breadcrumb"> 229 @Navigation.RenderNavigation(_navigationTemplate, _navigationSettings) 230 </div> 231 232 <img class="pview__top__brand" src="@alternativeImage"/> 233 </div> 234 235 <div class="d-flex flew-row flex-wrap"> 236 237 238 <div class="pview__row row z-0"> 239 240 <div class="col-12 col-lg-6"> 241 <div class="product-view-gallery-wrapper position-relative"> 242 <div class="swiper product-view-gallery"> 243 <div class="swiper-wrapper"> 244 245 @foreach (var image in images) 246 { 247 var imageSrc = ""; 248 if (!string.IsNullOrEmpty(image)) 249 { 250 Dynamicweb.VestjyskMarketing.Models.ResizeImageSettings imageSettings = new Dynamicweb.VestjyskMarketing.Models.ResizeImageSettings 251 { 252 Width = 1500, 253 Height = 1500, 254 Crop = "5", 255 Quality = 90, 256 Image = image 257 }; 258 259 imageSrc = Dynamicweb.VestjyskMarketing.Helpers.ImageHelper.ResizeImage(imageSettings); 260 } 261 else 262 { 263 imageSrc = "/Files/Images/missing_image.jpg"; 264 } 265 266 string altText = OttoSchachner.Api.AISeo.GetProductImageAlt(product.Id, Model.VariantId, Model.LanguageId, image).FirstOrDefault()?.Alt ?? string.Empty; 267 if (string.IsNullOrEmpty(altText)) 268 { 269 altText = Translate("product-image-alt", "Produkt billede ") + " " + images.IndexOf(image); 270 } 271 272 <div class="swiper-slide"> 273 <img alt="@altText" class="pview__image-container__image" src="@imageSrc"> 274 </div> 275 } 276 277 @if (images.Count() == 0) 278 { 279 <div class="swiper-slide"> 280 <img alt="Produkt billede 0" class="pview__image-container__image" src="/Files/Images/missing_image.jpg"> 281 </div> 282 } 283 284 </div> 285 </div> 286 287 @{ 288 if (signedIn && purchasable) 289 { 290 string favoriteLink = "/Default.aspx?ID=" + pageService.GetPageByNavigationTag(PageView.Current().AreaID, "FavoriteService").ID + "&ProductID=" + Model.Id + "&ProductVariantId=" + Model.VariantId + "&UserID=" + PageView.Current().User.ID + "&ReloadPage=false"; 291 bool isInFavoriteList = false; 292 var favoriteLists = Pageview.User.GetFavoriteLists(); 293 int favoriteListContainingProductId = 0; 294 string command = "add"; 295 new FavoriteListService().ClearCache(); 296 297 foreach (var favoriteList in favoriteLists) 298 { 299 isInFavoriteList = Pageview.User.IsProductInFavoriteList(favoriteList.ListId, product.Id, Model.VariantId); 300 301 if (isInFavoriteList) 302 { 303 favoriteListContainingProductId = favoriteList.ListId; 304 command = "remove"; 305 break; 306 } 307 } 308 309 <a data-command="@command" data-in-this-list="@favoriteListContainingProductId" data-url="@favoriteLink" href="javascript:void(0)" title="@Translate("add-or-remove-favorites")" class="product-list__favorite z-2"> 310 311 @if (isInFavoriteList) 312 { 313 <i class="fa-sharp fa-solid fa-heart"></i> 314 } 315 else 316 { 317 <i class="fa-regular fa-heart"></i> 318 } 319 320 </a> 321 } 322 } 323 <div class="product-view-gallery__navigation position-absolute top-50 translate-middle-y z-1 justify-content-between d-flex "> 324 <i class="os-chevron os-chevron--prev bi-chevron-left product-view-prev"></i > 325 <i class="os-chevron bi-chevron-right product-view-next"></i > 326 </div> 327 </div> 328 329 <div class="pview__thumbnails product-view-thumbs row g-3 mt-2 "> 330 @if (images.Count > 1) 331 { 332 var imagesArray = images.ToArray(); 333 334 for (int i = 0; 335 i < images.Count(); 336 i++) 337 { 338 Dynamicweb.VestjyskMarketing.Models.ResizeImageSettings imageSettings = new Dynamicweb.VestjyskMarketing.Models.ResizeImageSettings 339 { 340 Width = 750, 341 Height = 750, 342 Crop = "5", 343 Quality = 90, 344 Image = imagesArray[i] 345 }; 346 347 var imageSrc = Dynamicweb.VestjyskMarketing.Helpers.ImageHelper.ResizeImage(imageSettings); 348 349 int number = i + 1; 350 351 string altText = OttoSchachner.Api.AISeo.GetProductImageAlt(product.Id, Model.VariantId, Model.LanguageId, imagesArray[i]).FirstOrDefault()?.Alt ?? string.Empty; 352 if (string.IsNullOrEmpty(altText)) 353 { 354 altText = Translate("product-image-alt", "Produkt billede ") + " " + i; 355 } 356 357 <a title="@Translate("go-to-image", "Gå til billede ") @number" data-slide="@i" class="pview__thumbnails__item col-2 "> 358 <img alt="@altText" loading="lazy" src="@imageSrc"/> 359 </a> 360 } 361 } 362 363 </div> 364 365 @if (signedIn && isMobile == false) 366 { 367 @RenderSections() 368 } 369 370 </div> 371 <div class="col-12 col-lg-6"> 372 <h1 class="pview__name"> 373 @Model.Name 374 </h1 > 375 <div class="pview__productid "> 376 @Translate("product-number", "Varenr: ") @Model.Number 377 </div> 378 379 380 @if (purchasable) 381 { 382 <div class="pview__price d-flex flex-row align-items-center"> 383 <div class="pview__price__text me-3"> 384 <span class="pview__price__text"> 385 @Translate("recommended-price", "Vejl. pris") 386 </span> 387 </div> 388 <span class="pview__price__amount">@product.DefaultPrice.ToString("F2") KR. <span class="pview__price__amount__netto d-none">(@Translate("net-price", "netto") @Model.Price.PriceWithoutVatFormatted )</span></span> 389 390 </div> 391 392 <div class="pview__price-toggler d-flex flex-row mb-3"> 393 394 395 <div class="pview__price-toggler__container d-flex flex-row align-items-center"> 396 <input class="me-3" type="checkbox" id="pview__netprice" name="horns"/> 397 <label for="pview__netprice"> 398 @Translate("show-net-price", "Vis nettopris") 399 </label> 400 </div> 401 402 403 </div> 404 } 405 else if (signedIn == false) 406 { 407 <div class="pview__signin-message "> 408 @Translate("sign-in-to-see-prices", "LOG IND FOR AT SE PRISER OG KØBE PRODUKTET") 409 </div> 410 } 411 412 @if (purchasable) 413 { 414 @RenderPriceMatrix() 415 } 416 417 <div class="pview__description"> 418 @Model.ShortDescription 419 @Model.LongDescription 420 </div> 421 422 @{ 423 string pictogramHtml = Model.ProductFields["VjmPictogramHtml"]?.Value.ToString(); 424 if (!string.IsNullOrEmpty(pictogramHtml)) 425 { 426 <div class="pictogram__section d-flex"> 427 <div class="d-flex "> 428 @pictogramHtml 429 </div> 430 </div> 431 } 432 } 433 434 @if (Model.VariantCombinations().Count > 1 && string.IsNullOrEmpty(Model.VariantId) && signedIn) 435 { 436 <div class="pview__variant-selector__message mb-3 fw-bold"> 437 @Translate("select-variant-message", "Du skal vælge variant før du kan tilføje til kurv") 438 </div> 439 } 440 @{ 441 string variantGroupName = ""; 442 bool colorGroup = Model.VariantInfo.VariantInfoGroupName == "Farver"; 443 444 @if (Model.VariantGroups().Count > 0) 445 { 446 if (Model.VariantGroups().Count == 1) 447 { 448 variantGroupName = Model.VariantGroups().First().Name.Replace(" ",""); 449 variantGroupName = Translate("VariantGroup.Name." + variantGroupName, variantGroupName); 450 451 <div class="pview__cart__variant mb-3"> 452 <span class="fw-bold">@variantGroupName@(colorGroup ? ": " : "")</span> 453 @if (colorGroup) 454 { 455 <span>@Model.VariantName</span> 456 } 457 </div> 458 } 459 } 460 } 461 462 @if (signedIn && isMobile) 463 { 464 @RenderSections() 465 } 466 467 @{ 468 var step = Model.PurchaseQuantityStep; 469 if (step == null || step == 0) 470 { 471 step = 1; 472 } 473 474 string stockLevel = Convert.ToString(product != null ? product.ProductFieldValues["VjmStockLevel"]?.Value : Model.ProductFields["VjmStockLevel"]?.Value); 475 string stockLevelText = ""; 476 477 if (!string.IsNullOrEmpty(stockLevel)) 478 { 479 stockLevel = stockLevel.ToLower(); 480 stockLevelText = StockLevelText(stockLevel); 481 } 482 483 484 <div class="pview__cart"> 485 <div class="pview__variant-selector row g-2 mb-2 mb-lg-4 d-flex flex-row flex-wrap"> 486 487 @if (Model.VariantGroups().Count == 1) 488 { 489 @foreach (var variantGroup in Model.VariantGroups()) 490 { 491 foreach (var option in variantGroup.Options) 492 { 493 string variantUrl = "/Default.aspx?ID=" + Pageview.ID + "&groupid=" + Model.PrimaryOrDefaultGroup.Id + "&productid=" + Model.Id + "&variantid=" + option.Id; 494 var variantProduct = new ProductService().GetProductById(Model.Id, option.Id, Model.LanguageId); 495 496 @if (Model.VariantInfo.VariantInfoGroupName == "Farver") 497 { 498 var variantImagePath = productImageService.GetImagePath(variantProduct); 499 500 Dynamicweb.VestjyskMarketing.Models.ResizeImageSettings imageSettings = new Dynamicweb.VestjyskMarketing.Models.ResizeImageSettings 501 { 502 Width = 1500, 503 Height = 1500, 504 Crop = "5", 505 Quality = 90, 506 Image = variantImagePath 507 }; 508 509 string imageSrc = Dynamicweb.VestjyskMarketing.Helpers.ImageHelper.ResizeImage(imageSettings); 510 511 <div class="w-auto"> 512 <div class="pview__variant-selector__item"> 513 <a href="@variantUrl" title="@Translate("go-to", "Gå til") @variantGroupName.ToLower() @option.Name.ToLower()"> 514 <img class="w-100" alt="Variant @option.Name" src="@imageSrc"/> 515 </a> 516 </div> 517 </div> 518 } 519 else 520 { 521 <div class="w-auto"> 522 <div class="pview__variant-selector__item number-selector @(Model.VariantId == option.Id ? "active" : "")"> 523 <a href="@variantUrl" title="@Translate("go-to", "Gå til") @variantGroupName.ToLower() @option.Name.ToLower()" class="d-flex h-100 w-100 align-items-center justify-content-center text-decoration-none"> 524 @option.Name 525 </a> 526 </div> 527 </div> 528 } 529 } 530 } 531 } 532 //multi variant håndtering 533 else 534 { 535 <div hidden="" id="variant-combinations"> 536 @string.Join(",", Model.VariantCombinations()) 537 </div> 538 @foreach (var variantGroup in Model.VariantGroups()) 539 { 540 string variantGroupNameMulti = Translate("VariantGroup.Name." + variantGroup.Name, variantGroup.Name); 541 <div class="pview__cart__variant fw-bold"> 542 @variantGroupNameMulti 543 </div> 544 <div class="d-flex mb-1 flex-wrap"> 545 @{ 546 foreach (var option in variantGroup.Options) 547 { 548 string variantUrl = "/Default.aspx?ID=" + Pageview.ID + "&groupid=" + Model.PrimaryOrDefaultGroup.Id + "&productid=" + Model.Id + "&variantid=" + option.Id; 549 bool active = Model.VariantId.Contains(option.Id); 550 551 <div class="me-2 mb-2"> 552 <a data-group="@variantGroup.Name" data-id="@option.Id" data-url="@variantUrl" href="javascript:void(0)" title="@Translate("select", "vælg") @option.Name" class="os-button os-button--no-hover @(active ? "" : "active os-button--transparent") d-flex h-100 w-100 align-items-center justify-content-center text-decoration-none"> 553 @option.Name 554 </a> 555 </div> 556 } 557 } 558 </div> 559 } 560 } 561 </div> 562 563 @if (purchasable) 564 { 565 <form method="post" class="h-100"> 566 <div class="pview__cart__container d-flex align-items-stretch mb-3"> 567 <div class="col-4"> 568 <input name="Quantity" type="number" min="@step" step="@step" value="@step" class="pview__cart__container__quantity col-4"/> 569 </div> 570 <div class="col-8"> 571 572 <input type="hidden" name="ProductId" value='@Model.Id'/> 573 <input type="hidden" name="VariantId" value="@Model.VariantId"/> 574 <button class="pview__cart__container__button" type="submit" name="CartCmd" value="add">Tilføj til kurv</button> 575 576 </div> 577 </div> 578 </form> 579 <div class="d-flex flex-row align-items-center"> 580 <div class="col-4 d-flex flex-row justify-content-between align-items-center"> 581 <div class="pview__cart__min ">Min. antal: @step</div> 582 <div class="pview__cart__status-color pview__cart__status-color--@stockLevel"> 583 </div> 584 </div> 585 <div class="pview__cart__message d-flex align-items-center"> 586 @stockLevelText 587 </div> 588 </div> 589 } 590 </div>} 591 592 @if (signedIn == false) 593 { 594 @RenderSections() 595 } 596 </div> 597 </div> 598 </div> 599 </div> 600 601 @functions{ 602 603 string StockLevelText(string stockLevel) 604 { 605 string result = ""; 606 607 if (!string.IsNullOrEmpty(stockLevel)) 608 { 609 stockLevel = stockLevel.ToLower(); 610 611 switch (stockLevel) 612 { 613 case "green": 614 result = Translate("in-stock", "På lager"); 615 break; 616 case "yellow": 617 result = Translate("low-stock", "På vej hjem"); 618 break; 619 case "red": 620 result = Translate("out-of-stock", "Ikke på lager"); 621 break; 622 default: 623 result = Translate("out-of-stock", "Ikke på lager"); 624 break; 625 } 626 } 627 628 return result; 629 } 630 631 } 632 633 @if (Model.VariantCombinations().Count > 0) 634 { 635 var quickOrderVariants = product.GetVariantCombinations().Where(x => x.GetProduct(Model.LanguageId) != null && x.GetProduct(Model.LanguageId).Active).ToList(); 636 quickOrderVariants = quickOrderVariants.OrderBy(x => x.GetProduct(Model.LanguageId).Number).ToList(); 637 int count = 0; 638 <div class="pview__qorder"> 639 <div class="os-container"> 640 <div class="d-flex flex-column flex-lg-row justify-content-between flex-wrap mb-3 mb-lg-5"> 641 <div class="pview__qorder__header col-12 col-lg-auto mb-3 mb-lg-0"> 642 @Translate("quick-order", "Hurtig bestilling") 643 </div> 644 645 <div class="pview__qorder__input-container d-flex flex-row align-items-center col-12 col-lg-5"> 646 <i class="bi-search me-2"></i> 647 <input class="pview__qorder__input-container__input col-5" 648 placeholder='@Translate("quick-order-search", "Søg efter varenr., DB nr., materiale, størrelse m.m.")'/> 649 </div> 650 </div> 651 <form method="post" action=""> 652 653 654 <input type="hidden" name="cartcmd" value="addmulti"/> 655 <input type="hidden" name="redirect" value="false"/> 656 657 <div class="product-table"> 658 <div class="row header @(signedIn ? "signed-in" : "") @(Model.VariantGroups().Count > 1 ? "multi" : "")"> 659 <div>@Translate("order-variant-number", "Varenr.")</div> 660 661 @{ 662 List<string> variantGroupNames = new List<string>(); 663 } 664 665 @foreach (var variantGroup in Model.VariantGroups()) 666 { 667 string _variantGroupName = Translate("VariantGroup.Name." + variantGroup.Name, variantGroup.Name); 668 variantGroupNames.Add(_variantGroupName); 669 <div>@_variantGroupName</div> 670 } 671 672 673 <div>@Translate("db-number", "DB-nummer")</div> 674 <div>@Translate("ean-upc", "EAN/UPC")</div> 675 <div>@Translate("special-order-item", "Skaffevare")</div> 676 <div>@Translate("order-quantity", "Ordrekvantum")</div> 677 <div>@Translate("packaging", "Forpakning")</div> 678 @if (signedIn) 679 { 680 <div>@Translate("stock-status", "Lagerstatus")</div> 681 } 682 </div> 683 684 @{ 685 var matrixItems = new List<(Dynamicweb.Ecommerce.Products.Product Product, VariantCombination VariantComb, bool IsVariant)>(); 686 687 //hvis ingen varianter - hvis hovedproduktet i tabellen 688 if (quickOrderVariants.Count == 0) 689 { 690 matrixItems.Add((product, null, false)); 691 } 692 693 // Tilføj alle variants bagefter 694 foreach (var vc in quickOrderVariants) 695 { 696 matrixItems.Add((vc.GetProduct(Model.LanguageId), vc, true)); 697 } 698 } 699 700 <div class="row-wrapper"> 701 @foreach (var item in matrixItems) 702 { 703 count++; 704 705 706 var variant = item.Product; 707 var variantComb = item.VariantComb; 708 bool isVariant = item.IsVariant; 709 // DB-nummer (VjmDBNumber) 710 string dbNumber = 711 variant?.ProductFieldValues? 712 .GetProductFieldValue("VjmDBNumber")?.Value?.ToString() 713 ?? Translate("not-available", "N/A"); 714 715 // EAN 716 string EAN = !string.IsNullOrEmpty(variant?.EAN) 717 ? variant.EAN 718 : Translate("not-available", "N/A"); 719 720 string spStatus = variant?.ProductFieldValues.GetProductFieldValue("SpStatus")?.Value?.ToString().ToLower(); 721 722 if (spStatus == "skaffevare" || spStatus == "pris på forespørgsel") 723 { 724 spStatus = Translate("Yes", "Ja"); 725 } 726 else 727 { 728 spStatus = Translate("No", "Nej"); 729 } 730 731 string variantStockLevel = Convert.ToString(variant != null ? variant.ProductFieldValues["VjmStockLevel"]?.Value : "red"); 732 string variantStockLevelText = ""; 733 734 735 if (!string.IsNullOrEmpty(variantStockLevel)) 736 { 737 variantStockLevel = variantStockLevel.ToLower(); 738 variantStockLevelText = StockLevelText(variantStockLevel); 739 } 740 741 // Packaging (VjmUnitsConcat) 742 string packaging = 743 variant?.ProductFieldValues? 744 .GetProductFieldValue("VjmUnitsConcat")?.Value?.ToString() 745 ?? ""; 746 747 // Unit (VjmSalesUnit) 748 string unit = 749 variant?.ProductFieldValues? 750 .GetProductFieldValue("VjmSalesUnit")?.Value?.ToString() 751 ?? ""; 752 753 // Minimum order quantity 754 string minQty = variant?.PurchaseQuantityStep.ToString() ?? ""; 755 756 if (minQty == "0") 757 { 758 minQty = "1"; 759 unit = ""; 760 } 761 762 // Price 763 string bruttoPrice = $"{variant.DefaultPrice:0.00} KR"; 764 PriceContext priceContext = new PriceContext(Dynamicweb.Ecommerce.Common.Context.Currency, Dynamicweb.Ecommerce.Common.Context.Country, shop, Pageview.User, false, null); 765 string netPrice = $"{variant?.GetPrice(priceContext).PriceWithoutVATFormattedNoSymbol:00} KR"; 766 767 <div class="row data @(count % 2 == 0 ? "visible-index-even" : "") @(signedIn ? "signed-in" : "") @(Model.VariantGroups().Count > 1 ? "multi" : "")"> 768 <input type="hidden" name="ProductLoopCounter@(count)" id="ProductLoopCounter@(count)" value="@count"/> 769 <input type="hidden" name="ProductId@(count)" id="ProductId@(count)" value="@variant.Id"/> 770 @if (isVariant) 771 { 772 <input type="hidden" name="VariantId@(count)" value="@variantComb.VariantId"/> 773 } 774 775 <!-- Varenr. --> 776 <div class="d-flex justify-content-between d-lg-block"> 777 <span class="d-block d-lg-none">@Translate("order-variant-number", "Varenr.")</span> 778 <span class="searchable">@variant.Number</span> 779 </div> 780 <hr/> 781 <!-- Variantnavne --> 782 @if (isVariant) 783 { 784 int index = 0; 785 786 foreach (var optionId in variantComb.GetVariantOptionIds()) 787 { 788 <div class="d-flex justify-content-between d-lg-block"> 789 <span class="d-block d-lg-none">@variantGroupNames[index]</span> 790 <span class="searchable"> 791 @Model.VariantGroups().Find(group => group.Options.Find(option => option.Id == optionId) != null).Options.Single(option2 => option2.Id == optionId).Name 792 </span> 793 </div> 794 <hr/> 795 index++; 796 } 797 } 798 799 <!-- DB nummer --> 800 <div class="d-flex justify-content-between d-lg-block"> 801 <span class="d-block d-lg-none">@Translate("db-number", "DB-nummer")</span> 802 <span class="searchable">@dbNumber</span> 803 </div> 804 805 <hr/> 806 <!-- EAN --> 807 <div class="d-flex justify-content-between d-lg-block"> 808 <span class="d-block d-lg-none">@Translate("ean-upc", "EAN/UPC")</span> 809 <span class="searchable">@EAN</span> 810 </div> 811 <hr/> 812 813 <!-- Skaffevare --> 814 <div class="d-flex justify-content-between d-lg-block"> 815 <span class="d-block d-lg-none">@Translate("special-order-item", "Skaffevare")</span> 816 <span class="searchable">@spStatus</span> 817 </div> 818 819 <hr/> 820 <!-- Ordrekvantum --> 821 <div class="d-flex justify-content-between d-lg-block"> 822 <span class="d-block d-lg-none">@Translate("order-quantity", "Ordrekvantum")</span> 823 <span>@minQty @unit</span> 824 </div> 825 <hr/> 826 827 <!-- Forpakning --> 828 <div class="d-flex justify-content-between d-lg-block"> 829 <span class="d-block d-lg-none">@Translate("packaging", "Forpakning")</span> 830 <span>@packaging</span> 831 </div> 832 833 @if (signedIn) 834 { 835 <hr/> 836 <!-- Lagerstatus --> 837 <div class="d-flex justify-content-between d-lg-block align-items-center"> 838 <span class="d-block d-lg-none">@Translate("stock-status", "Lagerstatus")</span> 839 <div class="d-flex flex-row align-items-center p-0"> 840 <div class="pview__cart__status-color pview__cart__status-color--@variantStockLevel"></div> 841 @variantStockLevelText 842 </div> 843 </div> 844 845 <hr/> 846 847 <!-- Pris --> 848 <div class="d-flex justify-content-between d-lg-block flex-row flex-lg-column align-items-center"> 849 <span class="d-block d-lg-none">@Translate("price", "Pris")</span> 850 <div class="d-flex flex-column"> 851 <span class="fw-bold">@bruttoPrice</span> 852 <span class="quick-order-net d-none">(@netPrice)</span> 853 <small>@Translate("quick-order-min", "Bestilles i"): @minQty @unit</small> 854 </div> 855 856 </div> 857 <hr/> 858 859 <!-- Antal vælger --> 860 <div class="d-flex justify-content-between d-lg-block align-items-center"> 861 <span class="d-block d-lg-none">@Translate("quantity", "Antal")</span> 862 <div class="pview__qorder__actions d-flex flex-row"> 863 <a class="pview__qorder__actions__decrement" href="javascript:void(0)">-</a> 864 <input class="pview__qorder__actions__input" name="Quantity@(count)" type="number" step="@minQty" min="0" value="0"> 865 <a class="pview__qorder__actions__incremenet" href="javascript:void(0)">+</a> 866 </div> 867 </div> 868 } 869 </div> 870 } 871 872 </div> 873 </div> 874 875 876 <div class="pview__qorder__no-results justify-content-center mt-3" style="display: none"> 877 @Translate("quick-order-no-results", "Ingen resultater fundet") 878 </div> 879 880 @if (signedIn) 881 { 882 <div class="d-flex justify-content-end"> 883 <button type="submit" class="pview__qorder__add-button os-button os-button--red mt-4"> 884 @Translate("add-all-to-cart", "Læg alle i kurv") 885 </button> 886 </div> 887 } 888 </form > 889 890 </div> 891 </div> 892 } 893 894 @{ 895 var productListParameters = new Dictionary<string, object>(); 896 productListParameters.Add("itemsToShow", 4); 897 productListParameters.Add("maxItems", 99); 898 899 List<dynamic> productsRelated = new List<dynamic>(); 900 foreach (var relatedGroup in Model.RelatedGroups) 901 { 902 if (relatedGroup.Id == "TILBEHØR") 903 { 904 foreach (var relatedProduct in relatedGroup.Products) 905 { 906 productsRelated.Add(ProductInfoViewModelExtensions.GetProduct(relatedProduct)); 907 } 908 } 909 } 910 911 bool slider = productsRelated.Count > 4; 912 productListParameters.Add("slider", slider); 913 productListParameters.Add("products", productsRelated); 914 } 915 916 @if (productsRelated.Count > 0) 917 { 918 <div class="os-container pview__related"> 919 <div class="pview__related__header mb-4"> 920 @Translate("product-add-ons", "Tilbehør") 921 </div> 922 <div class="@(slider ? "" : "row g-3") "> 923 @RenderPartial("/Designs/OttoSchachner/Partials/ProductList.cshtml", new ParagraphViewModel(), productListParameters) 924 </div> 925 </div> 926 } 927 928 @if (signedIn == false) 929 { 930 <div class="os-container pview__signup"> 931 @{ 932 var signupParagraphPageId = GetPageIdByNavigationTag("NotSignedInProductViewParagraph"); 933 @(new Content(Pageview).RenderExternalGrid(signupParagraphPageId, "")) 934 } 935 </div> 936 }