Shopping bag
Loading orders...
Empty picture
Product ID: Total: 1 Price: 1.050.00 DKK DKK
DKK
Total price excl. VAT 1.239,20 DKK DKK Total price DKK
Exception in template (Designs\IBH\eCom/Product/PDP.cshtml): System.Exception: Error Running ExecuteReader: Execution Timeout Expired.  The timeout period elapsed prior to completion of the operation or the server is not responding., Sql: "SELECT
	                    -- Object columns
	                    O.DefinitionKey
	                    ,O.LastModified AS OjectLastModified
	                    ,O.ObjectId
	                    ,O.XmlObjectId
	                    ,O.ShopId
	                    ,O.LanguageId

	                    -- Value columns
	                    ,V.LastModified AS ValueLastModified
	                    ,V.XmlReferenceObjectId
	                    ,V.XmlReferenceObjectKey
	                    ,V.ValueId
	                    ,V.[Text]
                        ,V.FieldKey
                        ,V.SortOrder

                    FROM [LWI_Spec_Objects] AS O
                    JOIN [LWI_Spec_Values] AS V ON
	                    V.ShopId = O.ShopId
	                    AND V.LanguageId = O.LanguageId
	                    AND V.XmlObjectKey = O.DefinitionKey
	                    AND V.XmlObjectId = O.XmlObjectId
                    WHERE
                        O.DefinitionKey IN ('Product')
                        AND O.XmlObjectId IN ('187100','3692','3732','7895','245896')
                        AND O.ShopId IN ('SHOP1')
                        AND O.LanguageId IN ('LANG1')
                    ORDER BY O.DefinitionKey, O.LanguageId, O.ShopId, O.XmlObjectId
                    ", Params: '' ---> System.Data.SqlClient.SqlException: Execution Timeout Expired.  The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception: The wait operation timed out
   --- End of inner exception stack trace ---
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
   at Glimpse.Ado.AlternateType.GlimpseDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at NLWI.Platforms.Dynamicweb9.Database.ADatabaseRepository.ExecuteReader(String query, Object[] ps)
   --- End of inner exception stack trace ---
   at NLWI.Platforms.Dynamicweb9.Database.ADatabaseRepository.ExecuteReader(String query, Object[] ps)
   at NLWI.Platforms.Dynamicweb9.Specs.Repositories.SpecificationRepository.GetSpecificationObjects(HashSet`1 keys)
   at NLWI.Platforms.Dynamicweb9.Specs.Services.CachedSpecificationService.b__12_1(HashSet`1 k)
   at NLWI.Core.Platform.Caching.DictionaryCaching.GetOrInsert[TKey,TVal](HashSet`1 keys, Func`2 buildCacheKey, Func`2 lookupMethod, CacheOptions cacheOptions) in D:\VSO Agents\00TFS01-norriq-ip\_work\3\s\src\NLWI.Core\Platform\Caching\DictionaryCaching.cs:line 102
   at NLWI.Platforms.Dynamicweb9.Specs.Services.CachedSpecificationService.GetSpecificationObjects(HashSet`1 specificationObjectIdentifiers)
   at NLWI.Platforms.Dynamicweb9.Specs.Services.CachedProductSpecificationService.GetProductSpecifications(Dictionary`2 autoIdMappings)
   at NLWI.Platforms.Dynamicweb9.Specs.Services.CachedProductSpecificationService.GetProductSpecifications(HashSet`1 productAutoIds)
   at CompiledRazorTemplates.Dynamic.bceeabecafbb.Execute()
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context)
   at RazorEngine.Templating.TemplateService.Run(ITemplate template, DynamicViewBag viewBag)
   at RazorEngine.Templating.TemplateService.Parse(String razorTemplate, Object model, DynamicViewBag viewBag, String cacheName)
   at RazorEngine.Razor.Parse[T](String razorTemplate, T model, String cacheName)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()
@using System.Globalization @using NORRIQ.Common8.Razor; @using System.Linq @using Dynamicweb.Core @using Dynamicweb.Ecommerce.Products @using NORRIQ.Common8.Factory @using NLWI.Platforms.Dynamicweb9.Specs; @using StandardWebshop.CustomCode.Razor; @using StandardWebshop.CustomCode.CustomLogin.Branding.Service; @using StandardWebshop.CustomCode.Ecom.Stock @using NORRIQ.Common8.Caching @using NORRIQ.PcSysConnector.StockUpdate @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> @{ // The following line will prepare specs for both WhatAboutTheeseProducts and current product combining 5 sql to 1 ObjectFactory.GetInstance<NLWI.Platforms.Dynamicweb9.Specs.Services.IProductSpecificationService>().GetProductSpecifications(new HashSet<long>( GetLoop("eCom:Related.WhatAboutTheseProducts").Take(4).Select(a => a.GetLong("NIQ:ProductAutoId")).Concat(new[] { GetLong("NIQ:ProductAutoId") }) )); var specs = this.GetProductSpecifications(); var images = specs.GetAllByKey("Billeder"); var imageAlt = specs.GetByKey("ProductName").Value + ", " + specs.GetByKey("Brand").Value + ", " + specs.GetByKey("Designer").Value; var priceForContent = GetString("NIQ:PriceForGoogle"); var currency = GetString("Ecom:Product.Price.Currency.Code"); // Soldout / Limited supply // The point here is to provide IBH with a way of quickly managing the state of a product // without doing a full import from XPI. The stockNumber, soldOut and limitedSupply variables are used as follows: // 1) If stockNumber is less and 1, or the soldOut flag is true, the product cannot be bought. // 2) If the limitedSupply flag is set, the user will be notified of a limited supply, but the product can still be bought. // These 3 variables are all reset when doing a full import from XPI (Done via NLWI sync activities). var deliveryTimeValue = specs.GetByKey("LeveringsTid").GetReferenceSpecification().GetByKey("Id").Value; var isOrderingProduct = deliveryTimeValue.IndexOf("bestil", StringComparison.CurrentCultureIgnoreCase) > -1; var stockState = this.GetStockState(); var soldOut = (this.IsSoldOut() || stockState == StockState.OutOfStock || stockState == StockState.NoStockLocation); //var soldOut = (string.Equals(GetString("Ecom:Product:Field.Soldout.Value"), "true", StringComparison.OrdinalIgnoreCase) || stockNumber < 1) && !isOrderingProduct; var limitedSupply = this.IsLimitedSupply() || stockState == StockState.FewInStock; // CAS-25416-T2M8Z7: Projekt: Lagerstyring IBH online // NAV has the ability to override the stocklevel from XPI. As such, if the custom field "" on a product contains // data, that data should be displayed, and stock messages from XPI should be hidden. var stockFromNav = string.Equals(GetString("Ecom:Product:Field.StockPhase"), "L", StringComparison.OrdinalIgnoreCase); var stockPhaseDescription = GetString("Ecom:Product:Field.StockPhaseDesc"); var doNotIncludeSpecsList = new List<string> { "BrandLink", "BrandText", "BrandBanner" }; var giftlistLink = Navigation.GetUrlByNavigationTag("edit-giftlist"); List<Product> moreSaleProducts = this.GetMoreSaleProducts(specs.GetAllByKey("MoreSaleProducts").ToList(), Pageview.Area.EcomShopId); } <div class="container"> @DwCaching.CacheByPage("breadcrumb.xslt" + GetLong("NIQ:ProductAutoId"), () => RenderNavigation(new { Template = "Breadcrumb.xslt", Expandmode = "all", StartLevel = 1, EndLevel = 5 })) <section class="pdp" itemscope="" itemtype="https://schema.org/Product"> <div class="pdp-images"> <div class="pdp-images-inner"> @if (!isOrderingProduct || specs.GetByKey("LeveringsTid").GetReferenceSpecification().GetByKey("Id").Value == "Udsolgt" || !string.IsNullOrWhiteSpace(specs.GetByKey("BobbelTekst").Value)) { <span class="pdp-bobbeltekst"> @if (!isOrderingProduct) { if (soldOut) { <span class="pdp-label">@Translate("Soldtout", "Udsolgt")</span> } @*else if (limitedSupply) { <span class="pdp-label">@Translate("LImitedSupply", "Begrænset antal")</span> }*@ else if (!string.IsNullOrEmpty(stockPhaseDescription)) { @* Do not show anything as the XPI stock status should not be displayed when the stock is controlled by NAV. *@ } } @if (specs.GetByKey("LeveringsTid").GetReferenceSpecification().GetByKey("Id").Value == "Udsolgt") { <span class="pdp-label">@specs.GetByKey("Leveringstid").Value</span> } else if (string.Equals(specs.GetByKey("BobbelTekst").Value, "#")) { @* Do not show anything because "#" means that nothing should be showed (This is an XPI fix because it is not possible to delete values from XPI via the Excel import) *@ } else if (!string.IsNullOrWhiteSpace(specs.GetByKey("BobbelTekst").Value)) { <span class="pdp-label">@specs.GetByKey("BobbelTekst").Value</span> } </span> } @if (images.Any()) { var firstImage = images.First().Value; if (images.Count() > 1) { <div class="pdp-images-thumbs" id="pdp-thumbs"> <div class="pdp-thumb"> <img src="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=90&amp;Height=90&amp;Crop=5&amp;Compression=90", firstImage))" class="img-fluid" alt="@imageAlt" /> </div> @foreach (var image in images.Skip(1)) { <div class="pdp-thumb"> <img src="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=90&amp;Height=90&amp;Crop=5&amp;Compression=90",image.Value))" class="img-fluid" alt="@imageAlt" /> </div> } </div> <div class="pdp-images-view" id="pdp-images"> <a href="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=1200&amp;Crompression=90", firstImage))" class="pdp-image" data-fancybox="images" data-caption="@imageAlt" data-options='{"infobar": false, "animationEffect": false, "buttons":["zoom","close"]}'> <img src="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=500&amp;Height=500&amp;Crop=5&amp;Compression=90", firstImage))" class="img-fluid" itemprop="image" alt="@imageAlt" /> </a> @foreach (var image in images.Skip(1)) { <a href="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=1200&amp;Crompression=90", image.Value))" class="pdp-image" data-fancybox="images" data-caption="@imageAlt" data-options='{"infobar": false, "animationEffect": false, "buttons":["zoom","close"]}'> <img src="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=500&amp;Height=500&amp;Crop=5&amp;Compression=90", image.Value))" class="img-fluid" alt="@imageAlt" /> </a> } </div> } else { <a href="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=1200&amp;Crompression=90",images.First().Value))" class="pdp-image-lg" data-fancybox data-caption="@imageAlt" data-options='{"infobar": false, "animationEffect": false, "buttons":["zoom","close"]}'> <img src="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=500&amp;Height=500&amp;Crop=5&amp;Compression=90", images.First().Value))" class="img-fluid" itemprop="image" alt="@imageAlt" /> </a> } } </div> </div> <div class="pdp-details"> <div class="pdp-details-main"> <p class="pdp-brand" itemprop="brand"> @GetString("Ecom:Product:Field.Brand") </p> <h1 class="pdp-name" itemprop="name"> @GetString("Ecom:Product.Name") </h1> <div class="pdp-prices" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> @{ var currencyCode = Pageview.Area.EcomCurrencyId; var price = GetDouble("Ecom:Product.Discount.Price." + "PriceWithVAT" + ".Value"); var priceWithVat = GetDouble("Ecom:Product.Price.PriceWithVAT.Value"); var beforePrice = GetString("Ecom:Product:Field.Beforeprice.Value"); var isDiscount = priceWithVat != price; } @if (isDiscount || beforePrice.IsNotNullOrEmpty()) { <span class="pdp-org-price"> <span>@Translate("Before price", "Før ")</span> @if (isDiscount) { <span> @priceWithVat.ToString("N2") </span> } else { <span> @beforePrice </span> } <span>@currencyCode</span> </span> <span class="pdp-list-price"> <span>@Translate("After price", "Nu")</span> <span itemprop="price" content="@priceForContent">@price.ToString("N2")</span> <span itemprop="priceCurrency">@currencyCode</span> </span> } else { <span class="pdp-list-price"> <span itemprop="price" content="@priceForContent">@price.ToString("N2")</span> <span itemprop="priceCurrency" content="@currencyCode">@currencyCode</span> </span> } </div> <div class="pdp-buying"> @{ var canBuy = (!soldOut && deliveryTimeValue != "FremtidigKoeb") || isOrderingProduct; } @if (stockState != StockState.NotTracked) { if (limitedSupply) { <span class="pdp-stock-status"> @Translate("Få på lager") </span> } else if (stockState == StockState.InStock) { <span class="pdp-stock-status"> @Translate("På lager") </span> } } <form class="form" data-action="addToCart" id="[email protected]("Ecom:Product:Page.ID")" name="[email protected]("Ecom:Product:Page.ID")" method="post" action="@GetGlobalValue("Global:Pageview.Url.Raw")"> <input type="hidden" name="ProductURL" id="ProductURL" value="@UrlHelper.GetProductUrl(GetString("Ecom:Product.ID"))" /> <input type="hidden" name="CartCmd" id="CartCmd" value="addMulti" /> <input type="hidden" name="Redirect" id="Redirect" value="false" /> <input type="hidden" name="ProductLoopCounter1" id="ProductLoopCounter1" value="1"> <input type="hidden" name="ProductID1" id="ProductID1" value="@GetValue("Ecom:Product.ID")"> <input type="hidden" name="VariantID1" id="VariantID1" value="@GetString("Ecom:Product.VariantID")"> <input type="hidden" name="UnitID1" id="UnitID1" value="@GetString("Ecom:Product.DefaultUnitID")"> <input type="hidden" name="wishListID1" id="wishListID1" value="0"> <input type="hidden" name="custom_ProductNo" value="@GetString("Ecom:Product.Number")" /> <input type="hidden" name="custom_ProductName" value="@GetString("Ecom:Product.Name")" /> <input type="hidden" name="custom_ProductPrice" value="@GetDouble("Ecom:Product.Price.PriceWithVAT.Value").ToString("F2", new CultureInfo("en-US"))" /> <input type="hidden" name="custom_ProductCurrency" value="@currency" /> @if (!canBuy) { if (soldOut) { <p class="pdp-stock-status mb-0">@Translate("TemporaryUnavailable", "Varen er midlertidigt udsolgt.")</p> } else if (!string.IsNullOrEmpty(stockPhaseDescription)) { <p class="pdp-stock-status mb-0">@stockPhaseDescription</p> } else { <p class="pdp-stock-status mb-0">@specs.GetByKey("Leveringstid").Value</p> } } <div class="pdp-select"> @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> @using StandardWebshop.CustomCode.ViewModels.Variants; @{ var variants = GetLoop("VariantGroups").GetVariants(); // In IBH, the Product Number can be used as a unique product identifier. var currentProductNumber = GetString("Ecom:Product.Number"); // All variant products and their associated variant groups/options. var variantProducts = GetLoop("VariantCombinations").GetVariantProducts(variants, currentProductNumber); var productsDictionary = VariantViewModelBuilder.GetProductsInDimensionOrder(variants, variantProducts); var selectedVariant = VariantViewModelBuilder.GetSelectedOrEmpty(variantProducts); } @{ @* These lines are required because lazy load's its data. GetString("Ecom:VariantGroup.Label") GetString("Ecom:VariantGroup.Name") GetLoop("VariantAvailableOptions") GetString("Ecom:VariantOption.ID") GetString("Ecom:VariantOption.Name") *@ } @* // This will display all the different variants, and highlight the one currently being viewed. <h1>Test</h1> <ul> @foreach (var v1 in productsDictionary) { <li>@v1.Key.GroupName || @v1.Key.OptionId</li> <li> <ul> @foreach (var v2 in v1.Value) { <li @(v2.Value.IsSelected ? "style='font-weight:bold'" : "")>@v2.Key.GroupName || @v2.Key.OptionId ## <a href="@v2.Value.LinkToGroup">@v2.Value.Name</a></li> } </ul> </li> } </ul>*@ @if (variants.Count == 0) { @* No variants *@ } else if (variants.Count == 1) { var variantSelected = System.Web.HttpContext.Current.Request["Selected"] != null; <div class="pdp-variants pdp-variants-single"> <div class="form-group"> <label for="variant1Selector" class="sr-only">@Translate("Choose", "Vælg") <span class="text-lowercase">@selectedVariant.Variant1.GroupLabel</span></label> <select class="form-control" id="variant1Selector" data-enable-target="#buy-button"> <option value="0" @(!variantSelected ? "selected='selected'" : "")> @Translate("Choose", "Vælg") @selectedVariant.Variant1.GroupLabel </option> @foreach (var v1 in productsDictionary.Where(a => !string.IsNullOrEmpty(a.Key.OptionId))) { var isSelected = selectedVariant.Variant1.Equals(v1.Key); var product = v1.Value.First(); var linkToGroup = product.Value.LinkToGroup+ "&Selected=ready"; <option value="@(isSelected? "0" : v1.Key.OptionId)" @(isSelected && variantSelected ? "selected='selected'" : "") data-linktogroup="@linkToGroup">@v1.Key.OptionName</option> } </select> </div> </div> } else { <div class="pdp-variants pdp-variants-double"> <div class="form-group"> <label for="variant1Selector">@Translate("Choose", "Vælg") <span class="text-lowercase">@selectedVariant.Variant1.GroupLabel</span></label> <select class="form-control" id="variant1Selector"> @foreach (var v1 in productsDictionary.Where(a => !string.IsNullOrEmpty(a.Key.OptionId))) { var isSelected = selectedVariant.Variant1.Equals(v1.Key); <option value="@v1.Key.OptionId" @(isSelected ? "selected='selected'" : "")>@v1.Key.OptionName</option> } </select> </div> <div class="form-group"> <label for="variant2Selector">@Translate("Choose", "Vælg") <span class="text-lowercase">@selectedVariant.Variant2.GroupLabel</span></label> <select class="form-control" id="variant2Selector"> @foreach (var v1 in productsDictionary.Where(pde => pde.Key.Equals(selectedVariant.Variant1))) { foreach (var v2 in v1.Value.Where(a => !string.IsNullOrEmpty(a.Key.OptionId))) { var isSelected = selectedVariant.Variant2.Equals(v2.Key); <option value="@v2.Key.OptionId" @(isSelected ? "selected='selected'" : "") data-linktogroup="@v2.Value.LinkToGroup">@v2.Key.OptionName</option> } } </select> </div> </div> } <script type="text/x-jsrender" id="emptyVariant2OptionTemplate"> <option value="0"> @Translate("Choose", "Vælg") @selectedVariant.Variant1.GroupLabel </option> </script> <script type="text/x-jsrender" id="variant2OptionTemplate"> <option value="0"> @Translate("Choose", "Vælg") @selectedVariant.Variant2.GroupLabel </option> {{for Products}} <option value="{{:OptionId}}" data-linktogroup="{{:LinkToGroup}}">{{:OptionName}}</option> {{/for}} </script> <script append="true"> var variantData = [ @for (int i = 0; i < productsDictionary.Count; i++) { var v1 = productsDictionary.ElementAt(i); <text> { "GroupLabel": "@v1.Key.GroupLabel", "GroupName": "@v1.Key.GroupName", "OptionId": "@v1.Key.OptionId", "OptionName": "@v1.Key.OptionName", "Products": [ @for (int j = 0; j < v1.Value.Count; j++) { var v2 = v1.Value.ElementAt(j); <text> { "GroupLabel": "@v2.Key.GroupLabel", "GroupName": "@v2.Key.GroupName", "OptionId": "@v2.Key.OptionId", "OptionName": "@v2.Key.OptionName", "LinkToGroup": "@v2.Value.LinkToGroup" },@(j + 1 == v1.Value.Count ? "" : ",") </text> } ] },@(i + 1 == productsDictionary.Count ? "" : ",") </text> } ]; var variantMode = '@variants.Count'; var variantSelector = new AppStart.VariantSelector({ $emptyVariant2OptionTemplate: $('#emptyVariant2OptionTemplate'), $variant2OptionTemplate: $('#variant2OptionTemplate'), $v1Selector: $('#variant1Selector'), $v2Selector: $('#variant2Selector'), // 0 == no variants, 1 == single variant, 2 == 2 variants. variantMode: variantMode, variantData: variantData }); variantSelector.init(); @*require(['jquery', 'standardwebshop/areas/ecom/product/variantselection'], function($, variantSelection) { // 0 == no variants, 1 == single variant, 2 == 2 variants. var variantMode = @variants.Count; if (variantMode == 0) return; variantSelection.init({ $emptyVariant2OptionTemplate: $('#emptyVariant2OptionTemplate'), $variant2OptionTemplate: $('#variant2OptionTemplate'), $v1Selector: $('#variant1Selector'), $v2Selector: $('#variant2Selector'), // 0 == no variants, 1 == single variant, 2 == 2 variants. variantMode: variantMode, variantData: variantData }); });*@ </script> </div> <div class="pdp-select"> @if (canBuy) { <div class="pdp-qty"> <label for="Quantity1" class="sr-only">@Translate("Number", "Antal")</label> <div class="pdp-qty-control"> <input type="number" name="Quantity1" id="Quantity1" min="1" step="1" value="1" class="form-control" autocomplete="off" /> <button type="button" class="pdp-qty-decrease"> - </button> <button type="button" class="pdp-qty-increase"> + </button> </div> </div> var variantSelected = !GetLoop("VariantGroups").Any() || System.Web.HttpContext.Current.Request["Selected"] != null; <div class="pdp-button"> <button class="btn btn-primary btn-buying" id="buy-button" role="button" type="submit" @(!variantSelected ? "disabled=disabled" : @variantSelected.ToString())> <svg class="icon icon-xs"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#shopping"></use> </svg> <span class="loader loader-light loader-xs"></span> <span>@Translate("Add_to_cart", "Tilføj til kurv")</span> </button> </div> } else { <input type="hidden" name="Quantity1" id="Quantity1" value="1" /> } </div> @if (canBuy) { if (string.Equals(Pageview.Area.Culture, "nb-NO")) { <div class="add-to-gift-list"> <span data-action="addToGiftList">@Translate("Add to giftlist", "Tilføj til gaveliste")</span> </div> <p id="giftListSuccess" class="pdp-giftlist-added" style="display: none"> @Translate("Added to giftlist info", "Varen er tilføjet til din gaveliste") <a href="@giftlistLink"> @Translate("Show giftlist button", "Vis gaveliste") </a> </p> } } else { <div class="pdp-button"> <a data-fancybox data-src="#nostockModal" href="javascript:;" data-options='{"infobar": false, "smallBtn": false, "toolbar": false, "buttons":["close"]' class="btn btn-outline-dark btn-buying"> @Translate("nostock_btn", "Giv mig besked") </a> </div> } <div id="more-sale-input-container"></div> </form> @if (!canBuy) { var usermail = Pageview.User != null ? Pageview.User.Email : string.Empty; <div class="pdp-backinstock" id="nostockModal" style="display:none;"> <h2 class="modal-title">@Translate("modal_nostock_heading", "Giv mig besked")</h2> <p>@Translate("modal_nostock_txt", "Vi sender dig en e-mail, når denne vare igen er på lager.")</p> <form name="@GetValue("Ecom:Product.ID")" method="post" class="form validation pdp-backinstock-form" role="form" action=""> <input type="hidden" name="ProductID" value="@GetValue("Ecom:Product.ID")" /> <input type="hidden" name="VariantID" value="@GetValue("Ecom:Product.VariantID")" /> <input type="hidden" name="LanguageID" value="@GetValue("Ecom:Product.LanguageID")" /> <input type="hidden" name="ProductName" value="@specs.GetByKey("ProductName").Value" /> <input type="hidden" name="CartCmd" value="createnotificationforthisproduct" /> <div class="form-group"> <label for="NotificationEmail">@Translate("ns_email", "E-mail adresse")</label> <div class="form-group-combined"> <input name="NotificationEmail" id="NotificationEmail" type="email" value="@usermail" class="required form-control"> <button type="submit" class="btn btn-primary btn-block">@Translate("nostocksend_btn", "Send")</button> </div> </div> </form> </div> } </div> @{ var usps = specs.GetByKey("ProductUSP"); } @if (!usps.Value.IsNullOrEmpty()) { <ul class="pdp-usp"> <li class="pdp-usp-item"> <span class="pdp-usp-link"> <svg class="icon icon-xs"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#star"></use> </svg> <span> @usps.Value </span> </span> </li> </ul> } </div> <div id="pdp-details-data" class="pdp-details-data mt-3"> @if (moreSaleProducts.Any()) { <div class="pdp-more-sales"> <h3>@specs.GetByKey("MoreSaleHeadline").Value</h3> <div class="pdp-more-sales-container"> <div class="more-sale-images"> @PrintMoreSaleProductImage(moreSaleProducts, imageAlt) </div> <div class="more-sale-container"> @PrintMoreSaleProduct(moreSaleProducts, currencyCode) </div> </div> </div> } <div class="pdp-accordion" data-toggle="collapse" data-target="#pdp-details" aria-expanded="true" aria-controls="pdp-details" data-parent="#pdp-details-data"> <h3>@Translate("Product details", "Detaljer")</h3> </div> <div class="pdp-accordion-content collapse show" id="pdp-details"> @if (specs.GetByGroup("Produkt detaljer").Any()) { var specsToSkipLabels = specs.GetByKey("SkjulLabelPaaWeb").Value.Split(';'); <div class="pdp-specs"> <ul class="pdp-specs-list"> @foreach (var spec in specs.GetByGroup("Produkt detaljer").GroupBy(a => a.Key).Where(i => i.Key != "Barcode" && !doNotIncludeSpecsList.Contains(i.Key) && !string.Equals(i.Key, "ProductUSP", StringComparison.InvariantCultureIgnoreCase))) { var showLabel = !specsToSkipLabels.Contains(spec.First().Key); if (spec.First().Key == "Link") { <li class="pdp-specs-item"> <a href="@spec.First().Value" target="_blank">@spec.First().Caption</a> </li> } else if (spec.First().Key == "Leveringstid" && !string.IsNullOrEmpty(stockPhaseDescription)) { <li class="pdp-specs-item"> @(showLabel ? spec.First().Caption + ": " : "")@stockPhaseDescription </li> } else { <li class="pdp-specs-item"> @(showLabel ? spec.First().Caption + ": " : "")@String.Join(", ", spec.Select(a => a.Value)) </li> } } </ul> </div> } </div> <div class="pdp-accordion collapsed" data-toggle="collapse" data-target="#pdp-description" aria-expanded="false" aria-controls="pdp-description" data-parent="#pdp-details-data"> <h3>@Translate("Produkt beskrivelse", "Produkt beskrivelse")</h3> </div> <div class="pdp-accordion-content collapse" id="pdp-description"> @if (!string.IsNullOrEmpty(specs.GetByKey("Beskrivelse").Value)) { //Read the full text. var fullText = specs.GetByKey("Beskrivelse").Value;// + " " + specs.GetByKey("Beskrivelse").Value; <div class="pdp-description" itemprop="description"> <p>@fullText</p> </div> } </div> @if (GetBoolean("Ecom:Product:Field.VisLagerstatus")) { DateTime? lastWmsSyncDateTime = new StockUpdateInfo().GetLatestTimestamp(); <div class="pdp-accordion collapsed" data-toggle="collapse" data-target="#pdp-stock-locations" aria-expanded="false" aria-controls="pdp-stock-locations" data-parent="#pdp-details-data"> <h3>@Translate("Lagerstatus i butik")</h3> </div> <div class="pdp-accordion-content collapse" id="pdp-stock-locations"> <div class="pdp-stock-locations"> @{ foreach (var stockLocation in this.GetStockLocations()) { <div class="location-name"> <h6>@stockLocation.Name</h6> </div> <div class="pdp-stock-location"> <div class="stock-column location-info"> <div class="location-text"> @stockLocation.Address </div> </div> <div class="stock-column location-status"> <span class="icon @stockLocation.StockLocationState"></span> <span class="stock-text"> @if (stockLocation.StockLocationState == StockState.FewInStock.ToString()) { <span class="stock-status"> @Translate("Få på lager i butik") </span> } else if (stockLocation.StockLocationState == StockState.InStock.ToString()) { <span class="stock-status"> @Translate("På lager i butik") </span> } else if (stockLocation.StockLocationState == StockState.OutOfStock.ToString()) { <span class="stock-status"> @Translate("Ikke på lager i butik", "Udsolgt") </span> } </span> </div> <div class="stock-column location-opening-hours"> <a href="@stockLocation.Link">@Translate("Se åbningstider")</a> </div> </div> } } <div class="pdp-stock-updated"> @Translate("Dette er lagertal pr.") @lastWmsSyncDateTime. @Translate("Lagerstatus kan ændre sig flere gange om dagen. Tjek om varen stadig er på lager, inden du tager i butik, så du ikke går forgæves.") </div> </div> </div> } </div> <div class="pdp-details-foot"> <p> @if (!string.IsNullOrEmpty(specs.GetByKey("Barcode").Value)) { <span> @specs.GetByKey("Barcode").Caption: @specs.GetByKey("Barcode").Value </span> } else { <text>&nbsp;</text> } </p> <p> <a data-fancybox data-src="#shoppingGuide" href="javascript:;" data-options='{"infobar": false, "smallBtn": false, "toolbar": false, "buttons":["close"]'>@Translate("Need help", "Brug for hjælp?")</a> </p> </div> </div> </section> @*@if (GetLoop("eCom:Related.WhatAboutTheseProducts").Any()) { <section class="pdp-related" id="partnerloop"> <h2 class="text-center">@Translate("other_favorites_heading", "Andre favoritter")</h2> <ul class="plp-list"> @foreach (var product in GetLoop("eCom:Related.WhatAboutTheseProducts").Take(4)) { var plpSpecs = product.GetProductSpecifications(); var plpImage = plpSpecs.HasKey("Billeder") ? "/Files/Images/XPI/" + plpSpecs.GetByKey("Billeder").Value : "/Files/Images/Ecom/default.jpg"; var url = "/Default.aspx?ID=" + NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("webshop") + "&amp;ProductID=" + product.GetString("Ecom:Product.ID.UrlEncoded"); <li class="plp-list-item"> <article class="plp-list-product"> <a href="@url" itemprop="url" class="plp-list-url"> <figure class="plp-list-image"> <img src="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image={0}&amp;Width=220&amp;Height=220&amp;Crop=5&amp;Compression=90", plpImage))" class="img-fluid" alt="@product.GetString("Ecom:Product.Name")" itemprop="image" /> </figure> <header class="plp-list-info"> <p class="plp-list-brand" itemprop="brand"> @plpSpecs.GetByKey("Brand").Value </p> <h2 class="plp-list-name" itemprop="name"> @product.GetString("Ecom:Product.Name") </h2> </header> </a> <footer class="plp-list-prices"> @{ var pdpPrice = product.GetDouble("Ecom:Product.Price.PriceWithVAT.Value"); var pdpBeforeprice = product.GetString("Ecom:Product:Field.Beforeprice.Value"); } @if (pdpBeforeprice != "") { <span class="plp-org-price"> <span>@Translate("Before price", "Før ")</span> <span>@pdpBeforeprice</span> <span>@currencyCode</span> </span> <span class="plp-list-price"> <span>@Translate("After price", "Nu")</span> <span itemprop="price">@pdpPrice.ToString("N2")</span> <span itemprop="price">@currencyCode</span> </span> } else { <span class="plp-list-price"> <span itemprop="price">@pdpPrice.ToString("N2")</span> <span itemprop="priceCurrency">@currencyCode</span> </span> } </footer> </article> </li> } </ul> </section> }*@ </div> @{ var No1Banner = 0; if (!string.IsNullOrEmpty(Pageview.Area.Item["No1Banner"] as string)) { Int32.TryParse(Pageview.Area.Item["No1Banner"].ToString().Split('#').Last(), out No1Banner); } } @{ var imageLocation = ""; var imageText = ""; var brandPageLink = ""; var fallback = false; var xpiLocation = specs.GetByKey("BrandBanner").Value; //If there is data in XPI, get everything from there if (!string.IsNullOrWhiteSpace(xpiLocation.Trim())) { imageLocation = "/Files/Images/XPI/" + xpiLocation; imageText = specs.GetByKey("BrandText").Value; brandPageLink = specs.GetByKey("BrandLink").Value; } else { var brandingService = ObjectFactory.GetInstance<BrandingService> (); var brandName = specs.GetByKey("brand").Value; var brandPageInfo = brandingService.GetDwBrandPageInfo(brandName); var dwImageLocation = brandPageInfo.ImageLocation; if (!string.IsNullOrWhiteSpace(dwImageLocation)) { imageLocation = dwImageLocation; imageText = brandPageInfo.ImageText; brandPageLink = "/Default.aspx?ID=" + brandPageInfo.BrandPageId; } else if (No1Banner > 0) { fallback = true; //Render No1Banner as hidden and display it only if the user is not signed in <div id="no1bannertest" style="display: none;"> @RenderParagraphContent(No1Banner) </div> <script append="true"> $(document).ready(function () { var branding = new AppStart.BrandBannerHandler(); branding.init(); }); </script> } } if (!fallback && imageLocation.IsNotNullOrEmpty()) { <section class="banner"> <picture> <img src="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image={0}&amp;Width=2048&amp;Compression=90", imageLocation))" class="img-fluid" /> </picture> <div class="banner-content justify-content-center align-items-center"> <div class="banner-text text-center text-light bg-clear"> <h2 class="h1">@imageText</h2> <div class="btn-list"> <a href="@brandPageLink" class="btn btn-outline-light"> <span> @Translate("Læs mere", "Læs mere") </span> </a> </div> </div> </div> </section> } } <div id="addedModal" style="display:none;" class="fancybox-content"> @*<button class="btn-modal-close" data-fancybox-close> <svg class="icon"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#times"></use> </svg> </button>*@ <div class="fancybox-pdp-header"> <p class="h2"> <span data-bind="text: QuantityAdded"></span> @Translate("Products added to basket", "vare(r) tilføjet til kurven") </p> <p class="alert alert-warning" data-bind="visible: NoProductsAdded"> @Translate("Product not in stock", "Produktet er desværre ikke længere på lager og er derfor ikke tilføjet til kurven.") </p> <p class="alert alert-warning" data-bind="visible: QuantityAdjusted"> @Translate("Added product amount adjusted", "Obs. ikke tilstrækkelig på lager, antallet er nedjusteret.") </p> </div> <div class="fancybox-pdp-body"> <div class="fancybox-pdp-thumb"> <img data-bind="attr: { src: ProductImage}" src="" class="img-fluid" alt=""> </div> <div class="fancybox-pdp-product"> <div class="fancybox-pdp-name"> <span data-bind="text: Name"> </span> </div> <div class="fancybox-pdp-row"> <div class="fancybox-pdp-col"> <span class="fancybox-pdp-brand"> <span>@Translate("Brand", "Brand"):</span> <span data-bind="text: ProductBrand"></span> </span> <span class="fancybox-pdp-sku"> <span>@Translate("SKU", "Varenummer"):</span> <span data-bind="text: ProductNumber">12345678</span> </span> </div> <div class="fancybox-pdp-col"> <span class="fancybox-pdp-qty"> <span>@Translate("Quantity", "Antal"):</span> <span data-bind="text: QuantityAdded"></span> </span> <span class="fancybox-pdp-price"> <span><span data-bind="text: LinePrice"></span> @currency</span> </span> </div> </div> </div> </div> <div class="fancybox-pdp-navigation"> <a href="@NORRIQ.Common8.Razor.Navigation.GetUrlByNavigationTag(" cart")" class="btn btn-outline-dark"> @Translate("Show cart", "Vis kurv") </a> <a href="@NORRIQ.Common8.Razor.Navigation.GetUrlByNavigationTag(" checkout")" class="btn btn-secondary"> @Translate("Checkout", "Checkout") </a> </div> </div> <div id="giftlistLogin" data-action="submitLogin" style="display: none" class="fancybox-content loginFeedback"> <form method="post" id="testForm"> <h2>@Translate("giftlist", "Gaveliste")</h2> <span>@Translate("giftlist_not_loggedin", "Du bedes logge ind for at kunne tilføje til din gaveliste.")</span> <h3>@Translate("login_pop_header", "Log ind")</h3> <div class="form-group"> <label for="giftListUsername">@Translate("usernameLabel", "Brugernavn")</label> <input id="giftListUsername" name="Username" type="text" value="" class="form-control" required> </div> <div class="form-group"> <label for="giftListPassword">@Translate("password", "Adgangskode")</label> <input id="giftListPassword" name="Password" type="password" value="" class="form-control" required> </div> <div id="giftListloginFeedback"></div> <p class=""> <button type="submit" role="button" class="btn btn-primary btn-block" id="giftListloginBtn">@Translate("buttonLogin", "Log ind")</button> </p> @{ var giftListPasswordUrl = Navigation.GetUrlByNavigationTag("forgot-password"); var giftListNewUserUrl = Navigation.GetUrlByNavigationTag("new-user"); } <div class="loginFeedback" style="display: none;"> <p class="alert alert-warning"> @Translate("Cart Login Error", "Har du glemt dit brugernavn eller adgangskode?") <a href="@NORRIQ.Common8.Razor.Navigation.GetUriByNavigationTag("forgot-password")">@Translate("Cart Login Error Label", " Så klik her")</a> </p> </div> <ul class="list-unstyled"> <li> <a href="@giftListPasswordUrl" class="forgot-password">@Translate("label_forgotten_password", "Glemt adgangskode")</a> </li> <li> <a href="@giftListNewUserUrl">@Translate("label_create_new_user", "Opret ny bruger")</a> </li> </ul> </form> </div> @{ var shoppingGuide = 0; var createNo1 = 0; var infoNo1 = 0; var returnID = 0; if (!string.IsNullOrEmpty(Pageview.Area.Item["ShoppingGuide"] as string)) { Int32.TryParse(Pageview.Area.Item["ShoppingGuide"].ToString().Split('#').Last(), out shoppingGuide); } if (!string.IsNullOrEmpty(Pageview.Area.Item["No1CreateUser"] as string)) { Int32.TryParse(Pageview.Area.Item["No1CreateUser"].ToString().Split('#').Last(), out createNo1); } if (!string.IsNullOrEmpty(Pageview.Area.Item["No1Infotext"] as string)) { Int32.TryParse(Pageview.Area.Item["No1Infotext"].ToString().Split('#').Last(), out infoNo1); } if (!string.IsNullOrEmpty(Pageview.Area.Item["ShoppingTerms"] as string)) { Int32.TryParse(Pageview.Area.Item["ShoppingTerms"].ToString().Split('#').Last(), out returnID); } } @if (shoppingGuide > 0) { <div id="shoppingGuide" style="display:none;" class="fancybox-content"> @RenderParagraphContent(shoppingGuide) </div> } @if (createNo1 > 0 && infoNo1 > 0) { <div id="createNo1" style="display:none;" class="fancybox-content"> <h2 class="h1">@Translate("Opret dig som No1 kunde", "Opret dig som No1 kunde")</h2> @RenderParagraphContent(infoNo1) @RenderParagraphContent(createNo1) </div> } @if (returnID > 0) { <div id="returnID" style="display:none;" class="fancybox-content"> @RenderParagraphContent(returnID) </div> } @* Facebook Pixel tracking, CAS-25405-W5J7V5 *@ <script append="true"> if (typeof fbq !== "undefined") { fbq('track', 'ViewContent', { content_ids: ['@GetString("Ecom:Product.Number")'], content_type: 'product', content_name: '@specs.GetByKey("ProductName").Value', value: @GetDouble("Ecom:Product.Price.PriceWithVAT.Value").ToString("F2", new CultureInfo("en-US")), currency: '@currency' }); }; //TODO: Ulf tilføj dette til TS for PDP!!! $('.pdp-qty-increase').click(function() { var $input = $(this).parents('.pdp-qty-control').find('.form-control'); var val = parseInt($input.val(), 10); $input.val(val + 1); }); $('.pdp-qty-decrease').click(function() { var $input = $(this).parents('.pdp-qty-control').find('.form-control'); var val = parseInt($input.val(), 10); if (val > 1) { $input.val(val - 1); } }); </script> <script append="true"> $(document).ready(function () { var giftList = new AppStart.GiftList; giftList.init(); }); </script> @helper PrintMoreSaleProductImage(List<Product> moreSaleProducts, string imageAlt) { int index = 0; foreach (var moreSalesProduct in moreSaleProducts) { var moreSalesSpecs = ProductSpecificationExtensionMethods.GetProductSpecifications((int)moreSalesProduct.AutoId); var moreSalesProductImages = moreSalesSpecs.GetAllByKey("Billeder"); <a href="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=1200&amp;Crompression=90", moreSalesProductImages.First().Value))" @if (index == 0) { <text>class="pdp-image-lg more-sale-image active"</text> } else { <text>class="pdp-image-lg more-sale-image"</text> } data-fancybox data-caption="@imageAlt" data-options='{"infobar": false, "animationEffect": false, "buttons":["zoom","close"]}' data-id="@moreSalesProduct.Id"> <img src="@Pageview.CdnWrap(string.Format("/Admin/Public/GetImage.ashx?Image=/Files/Images/XPI/{0}&amp;Width=110&amp;Height=110&amp;Crop=5&amp;Compression=90", moreSalesProductImages.First().Value))" class="img-fluid" itemprop="image" alt="@imageAlt" /> </a> index++; } } @helper PrintMoreSaleProduct(List<Product> moreSaleProducts, string currencyCode) { // We have to start at index 2, because index 1 is the main product. int index = 2; foreach (var moreSalesProduct in moreSaleProducts) { string val = "value=\"" + index + "\""; <div class="more-sale-row"> <div class="more-sale-column radio"> <div class="form-check"> <input type="checkbox" name="more-sale-product" id="[email protected]" value="@moreSalesProduct.Id" class="more-sale-product" data-index="@{@index}" style="display: none;" /> <label for="[email protected]" class="custom-checkbox-label"> <svg class="icon"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#check"></use> </svg> </label> </div> <div class="more-sale-input"> <input type="hidden" name="[email protected]{@index}" id="[email protected]{@index}" @val> <input type="hidden" name="[email protected]{@index}" id="[email protected]{@index}" value="@moreSalesProduct.Id"> <input type="hidden" name="[email protected]{@index}" id="[email protected]{@index}" value="@moreSalesProduct.VariantId"> <input type="hidden" name="[email protected]{@index}" id="[email protected]{@index}" value="@moreSalesProduct.DefaultUnitId"> <input type="hidden" name="[email protected]{@index}" id="[email protected]{@index}" value="0"> <input type="hidden" name="[email protected]{@index}" value="1" /> </div> </div> <div class="more-sale-column name"> <a href="@UrlHelper.GetProductUrl(moreSalesProduct.Id)"> @moreSalesProduct.Name </a> </div> <div class="more-sale-column price"> <label for="[email protected]"> @moreSalesProduct.Price.PriceWithVAT.ToString("N2") <span itemprop="priceCurrency" content="@currencyCode">@currencyCode</span> </label> </div> </div> index++; } }