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