Exception in template (Designs\StandardWebshop\eCom/Product/Product.cshtml): System.Data.SqlClient.SqlException (0x80131904): Transaction (Process ID 63) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
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.TryHasMoreRows(Boolean& moreRows)
at System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
at System.Data.SqlClient.SqlDataReader.Read()
at Glimpse.Ado.AlternateType.GlimpseDbDataReader.Read()
at NLWI.Platforms.Dynamicweb8.Specs.Repositories.SpecificationRepository.GetSpecificationObjects(HashSet`1 keys) in D:\VSO Agents\00TFS01-norriq-ip\_work\134\s\NLWI.Platforms.Dynamicweb8.Specs\Repositories\SpecificationRepository.cs:line 267
at NLWI.Platforms.Dynamicweb8.Specs.Services.CachedSpecificationService.b__12_1(HashSet`1 k) in D:\VSO Agents\00TFS01-norriq-ip\_work\134\s\NLWI.Platforms.Dynamicweb8.Specs\Services\CachedSpecificationService.cs:line 91
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\35\s\src\NLWI.Core\Platform\Caching\DictionaryCaching.cs:line 102
at NLWI.Platforms.Dynamicweb8.Specs.Services.CachedSpecificationService.GetSpecificationObjects(HashSet`1 specificationObjectIdentifiers) in D:\VSO Agents\00TFS01-norriq-ip\_work\134\s\NLWI.Platforms.Dynamicweb8.Specs\Services\CachedSpecificationService.cs:line 88
at NLWI.Platforms.Dynamicweb8.Specs.Services.ProductSpecificationService.GetProductSpecifications(HashSet`1 productAutoIds) in D:\VSO Agents\00TFS01-norriq-ip\_work\134\s\NLWI.Platforms.Dynamicweb8.Specs\Services\ProductSpecificationService.cs:line 41
at NLWI.Platforms.Dynamicweb8.Specs.Services.ProductSpecificationService.GetProductSpecifications(Int64 productAutoId) in D:\VSO Agents\00TFS01-norriq-ip\_work\134\s\NLWI.Platforms.Dynamicweb8.Specs\Services\ProductSpecificationService.cs:line 68
at NLWI.Platforms.Dynamicweb8.Specs.ProductSpecificationExtensionMethods.GetProductSpecifications(Int32 autoId) in D:\VSO Agents\00TFS01-norriq-ip\_work\134\s\NLWI.Platforms.Dynamicweb8.Specs\ProductSpecificationExtensionMethods.cs:line 48
at NLWI.Platforms.Dynamicweb8.Specs.ProductSpecificationExtensionMethods.GetProductSpecifications[T](RazorTemplateBase`1 page) in D:\VSO Agents\00TFS01-norriq-ip\_work\134\s\NLWI.Platforms.Dynamicweb8.Specs\ProductSpecificationExtensionMethods.cs:line 24
at CompiledRazorTemplates.Dynamic.ebfaebeeddae.Execute()
at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context)
at RazorEngine.Razor.Parse[T](String razorTemplate, T model, String cacheName)
at Dynamicweb.Rendering.Template.Output()
ClientConnectionId:56d56cbc-8b81-44b5-ace0-738e9cbdf814
Error Number:1205,State:51,Class:13
@using System.Web
@using NORRIQ.Universal.Extensions
@using NORRIQ.Common8.Context
@using System.Web.Mvc.Html
@using Dynamicweb.NewsLetterV3
@using Newtonsoft.Json
@using NORRIQ.Common8.Ecom
@using NORRIQ.Common8.Factory
@using StandardWebshop.CustomCode.Razor
@using NORRIQ.Common8.Razor;
@using Dynamicweb.eCommerce.Common;
@using Dynamicweb.eCommerce.Products
@using NLWI.Platforms.Dynamicweb8.Specs;
@using StandardWebshop.CustomCode.Volumenpriser;
@using StandardWebshop.CustomCode.ProductFees;
@using StandardWebshop.CustomCode.ColorLookup
@using StandardWebshop.CustomCode.Units
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@{
var user = Dynamicweb.Modules.UserManagement.User.GetCurrentUser();
var isPrivate = GetBoolean("Ecom:Product:Field.PRIVATE.Value");
if (user == null && isPrivate)
{
//Redirect to 404 if product is a private, and you are not logged in, to avoid google from finding the products.
HttpContext.Current.Response.Redirect("/admin/public/404.aspx");
}
var hidePrices = false;
if (user != null)
{
hidePrices = user.CustomFieldValues.FirstOrDefault(cf => cf.CustomField.SystemName == "AccessUser_HidePrices").Value.ToString().ToLower() == "true" ? true : false;
}
//GetLoop("Units").Select(u => new
//{
// UnitId = u.GetString("Ecom:VariantOption.ID"),
// // Change the number format here:
// UnitPriceDouble = (u.GetDouble("Ecom:VariantOption.Price.PricePIP") / 100d),
// UnitName = u.GetString("Ecom:VariantOption.Name"),
// CurrencyCode = u.GetString("Ecom:VariantOption.Price.Currency.Code"),
// UnitObj = u
//}).OrderBy(x => x.UnitPriceDouble);
var tableModeBinding = "default";
// EcomMedia settings
var image = NORRIQ.EcomMedia.Frontend.GetProductMedia(this);
var docs = NORRIQ.EcomMedia.Frontend.GetProductMedia(this);
//XPI
var specs = this.GetProductSpecifications();
var SpecImages = specs.GetAllByKey("Image");
var SpecVideos = specs.GetAllByKey("YouTubeLinks");
// Product
var ProductCurrency = Context.Currency.Symbol;
var Productsheet = Translate("Productsheet", "Datablad");
//var AsyncKey = Pageview.User.LoggedIn ? this.GetJsonPriceKey() : "";
//var AsyncPrices = Pageview.User.LoggedIn ? this.GetJsonRetailPrice() : "";
//var ProductInfo = Pageview.User.LoggedIn ||
//var ShortDescription = GetString("Ecom:Product.LongDescription").Substring(0, 300) + "...";
//var ProductArea = GetGlobalValue("Global:Area.Lang");
var pricePForGoogle = GetString("NIQ:PriceForGoogle");
// Related products
var Columns = "col-xs-12 col-sm-4 col-md-4";
var ListMode = ObjectFactory.GetInstance<AreaItemSettings>().GetCurrentAreaValue<string>("ShowRelateproductsAsSlider");
// List mode
var mode = ObjectFactory.GetInstance<TemporarilySettings>().GetAndUpdate("listmode") ?? "" + ObjectFactory.GetInstance<AreaItemSettings>().GetCurrentAreaValue<string>("ProductlistMode") + "";
var volumenpriser = this.GetVolumenpriser();
var productFees = this.GetProductFees();
var productUnitInformation = this.GetUnitInformation();
var units = productUnitInformation.Units;
var defaultUnitId = productUnitInformation.ProductDefaultUnitId;
var packingSpec = specs.GetByGroup("Specifikationer").FirstOrDefault(x => x.Key == "Pakning");
var isTilbud = GetBoolean("Ecom:Product:Field.Tilbud.Value");
isTilbud = isTilbud || units.Any(x => x.IsInformativePrice);
var isNewProduct = GetBoolean("Ecom:Product:Field.Nyhed.Value");
var isOutlet = GetBoolean("Ecom:Product:Field.Outlet.Value");
bool productScope_discountedCompletely = GetBoolean("NIQ:Product.DiscontunedCompletely");
bool productScope_discountedTemporary = GetBoolean("NIQ:Product.DiscontunedTemporary");
bool productScope_isSubstituteProduct = productScope_discountedCompletely || productScope_discountedTemporary;
bool isVolumePriceDiscount = volumenpriser.HasPrices() && volumenpriser.IsValid();
var isFavoriteList = (System.Web.HttpContext.Current.Request["favoriteMode"] ?? string.Empty).Equals("true", StringComparison.InvariantCultureIgnoreCase);
}
<span style="display: none; visibility: hidden" data-product-key-clean='@(GetString("Ecom:Product.ID"))'></span>
@using System.CodeDom
@using Dynamicweb.Rendering
@using NLWI.Platforms.Dynamicweb8.Specs.ViewModels
@using NORRIQ.Common8.Context
@using NORRIQ.Common8.Factory
@using StandardWebshop.CustomCode.ColorLookup
@using StandardWebshop.CustomCode.Razor
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@helper RenderFavoriteListIcon(Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>.LoopItem product, string renderType = "grid")
{
var addFav = Translate("label_make_favorite", "Føj til favoritter");
var delFav = Translate("label_remove_favorite", "Fjern fra favoritter");
@RenderFavoriteListIcon(product.GetString("Ecom:Product.ID"), renderType)
}
@helper RenderFavoriteListIcon(Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> product, string renderType = "grid")
{
@RenderFavoriteListIcon(product.GetString("Ecom:Product.ID"), renderType)
}
@helper RenderFavoriteListIcon(string productKey, string renderType)
{
<ordering-list-item-condition inline-template>
<div class="basic_favoriteitem_wrapper">
<customer-agreement-item product-key="@productKey"></customer-agreement-item>
<template v-if="isAllowed">
<ordering-list-add-remove-item v-if="isAdvancedAdmin" product-key="@productKey"></ordering-list-add-remove-item>
<ordering-list-item product-key="@productKey"></ordering-list-item>
</template>
<template v-else>
<favorite-item product-key="@productKey"></favorite-item>
</template>
</div>
</ordering-list-item-condition>
}
@using System.Globalization
@using NLWI.Platforms.Dynamicweb8.Specs.ViewModels
@using NORRIQ.Common8.Factory
@using StandardWebshop.CustomCode.ColorLookup
@using StandardWebshop.CustomCode.Razor
@helper RenderSpecifications(ProductSpecifications specs, string renderType, params string[] excludeSpecKeys)
{
//Helper function to render specifications
//Exclude specfications by providing a parameter string to the function. ex.: RenderSpecifications(specs, "table", "BrandSymbol")
//Include all: RenderSpecifications(specs, "table")
var colorLookupService = ObjectFactory.GetInstance<ColorLookupService>();
bool firstTh = true;
bool firstTd = true;
if (renderType.Contains("table"))
{
<table class="table table-striped spectable">
<tbody>
@foreach (var spec in specs.GetByGroup("Specifikationer").GroupBy(a => a.Key))
{
if (excludeSpecKeys != null && excludeSpecKeys.Contains(spec.Key))
{
continue;
}
<tr>
<th class="@(firstTh ? "th-first" : "")">
@spec.First().Caption
</th>
<td class="@(firstTd ? "td-first" : "")">
@if (spec.Key == "Vaskeanvisninger")
{
foreach (var maerkeSpec in spec)
{
if (spec.Key == "Vaskeanvisninger")
{
<img src="/Admin/Public/GetImage.ashx?Width=46&Height=30&Compression=80&Image=/Files/Images/Symbol/@maerkeSpec.Value" alt="@maerkeSpec.Value" class="img-responsive" />
}
}
}
else if (spec.Key == "Farve")
{
var colorList = spec.Select(a => new
{
value = a,
color = colorLookupService.GetColorKey(a.Value)
});
if (colorList != null)
{
int colorIndex = 0;
foreach (var colorObj in colorList)
{
if (renderType.Contains("PDF"))
{
//use inline style if PDF
<span class="spec-color [email protected]" style="background-color:@colorObj.color; border-color:@(colorObj.color.Contains("White") ? "#ccc": colorObj.color)"></span>
<span>@(colorIndex > 1 ? ", " : string.Empty)@colorObj.value.Value </span>
}
else
{
<span class="spec-color [email protected]"></span>
}
colorIndex++;
}
}
}
else if (spec.Any(s => SpecificationHelper.IsImageFile(s.Value)))
{
foreach (var s in spec)
{
if (SpecificationHelper.IsImageFile(s.Value))
{
<img src="/Admin/Public/GetImage.ashx?Width=60&Height=60&Compression=80&Crop=5&Image=/Files/Images/XPI/@s.Value" alt="@s.Value" class="img-responsive" />
}
else
{
@s.Value
}
}
}
else if (spec.First().Caption.Contains("(kg)"))
{
var weightString = String.Join(", ", spec.Select(a => a.Value));
double weightDouble = 0;
if (double.TryParse(weightString, NumberStyles.AllowDecimalPoint, new CultureInfo("en-US") ,out weightDouble))
{
@weightDouble
}
else
{
@weightString
}
}
else
{
@String.Join(", ", spec.Select(a => a.Value))
}
</td>
</tr>
firstTd = false;
firstTh = false;
}
</tbody>
</table>
}
else if (renderType.Equals("Unknown"))
{
//Replace this renderType if needed.
}
}
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@helper RenderStockInformations(Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>.LoopItem product, bool disableStock = false)
{
var stock = product.GetDouble("Ecom:Product.Stock");
var isStykliste = product.GetBoolean("Ecom:Product:Field.Stykliste.Value");
var isSkaffevare = product.GetBoolean("Ecom:Product:Field.Skaffevare.Value");
var isOutlet = product.GetBoolean("Ecom:Product:Field.Outlet.Value");
@*<p>disable stock: @disableStock</p>*@
if (isSkaffevare && stock == 0)
{
<i class="icon-stock icon-blue" title="@Translate("label_skaffevare", "Skaffevare")"></i>
<span class="stock-label-text">@Translate("label_skaffevare", "Skaffevare")</span>
}
else
{
if (disableStock)
{
<i class="icon-stock icon-red" title="@Translate("label_out__of_stock", "Udgået")"></i>
<span class="stock-label-text">@Translate("label_out__of_stock", "udgået")</span>
}
else if (stock < 1 && !isStykliste)
{
<i class="icon-stock icon-yellow" title="@Translate("label_in_stock_in_x_days", "Forventes på lager indenfor 4 dage.")"></i>
<span class="stock-label-text">@Translate("label_in_stock_in_x_days_short", "Ikke på lager")</span>
}
else
{
<i class="icon-stock icon-green" title="@stock"></i>
if (isOutlet)
{
<span class="stock-label-text" style="display: inline;">@stock @Translate("label_in_stock", "In stock")</span>
}
else
{
<span class="stock-label-text">@Translate("label_in_stock", "In stock")</span>
}
}
}
}
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@helper RenderProductLabels(bool isTilbud, bool isVolumePriceDiscount, bool discountedCompletely, bool discountedTemporary, bool isNyhed, bool isOutlet, string renderType = "")
{
bool isSubstituteProduct = discountedCompletely || discountedTemporary;
@*<p>isTilbud: @isTilbud</p>
<p>isVolumePriceDiscount: @isVolumePriceDiscount</p>
<p>discountedCompletely: @discountedCompletely</p>
<p>discountedTemporary: @discountedTemporary</p>
<p>isNyhed: @isNyhed</p>
<p>isOutlet: @isOutlet</p>*@
if (isNyhed && renderType == "")
{
<div class="label-wrap label-wrap-bottom">
<span class="labl news">@Translate("Label_Nyhed", "Nyhed")</span>
</div>
}
<div class="label-wrap">
@if (!isSubstituteProduct)
{
<span class="pricing js-hide-before">
<span class="labl spar">
@Translate("Spar")
<span class="async-price-discount"></span>
</span>
@*<br> //AG but why?*@
</span>
if (isVolumePriceDiscount)
{
<span class="labl tilbud">@Translate("Label_VolumenPrisTilbud", "Volumen rabat")</span>
}
else if (isTilbud)
{
<span class="labl tilbud">@Translate("Tilbud")</span>
}
if (isNyhed && renderType == "PDP")
{
<span class="labl news">@Translate("Label_Nyhed", "Nyhed")</span>
}
}
else
{
if (discountedCompletely)
{
<span class="labl discontinued">@Translate("erstatningsvare_udgaaet", "Udgået vare")</span>
}
else if (discountedTemporary)
{
<span class="labl temporarily">@Translate("erstatningsvare_temporarily", "Midlertidigt udgået")</span>
}
}
</div>
}
@using System.CodeDom
@using Dynamicweb.Rendering
@using Newtonsoft.Json
@using NLWI.Platforms.Dynamicweb8.Specs.ViewModels
@using NORRIQ.Common8.Context
@using NORRIQ.Common8.Factory
@using StandardWebshop.CustomCode.ColorLookup
@using StandardWebshop.CustomCode.Razor
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@helper RenderBuyButton(Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>.LoopItem product, string renderType = "grid")
{
//temp track object - remove when converting to clean VUE
var loopItemProductJson = new
{
//NOTE: name not working if dangurous characthers
//Name = System.Web.HttpUtility.HtmlEncode(product.GetString("Ecom:Product.Name")).Replace("\"", "'"),
Number = string.Format("[{0}]", product.GetString("Ecom:Product.Number")),
};
<div v-fbq-track.addtocart='@JsonConvert.SerializeObject(loopItemProductJson)'>
@RenderBuyButton(product.GetString("Ecom:Product.ID"), renderType)
</div>
}
@helper RenderBuyButton(Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> product, string renderType = "grid")
{
//temp track object - remove when converting to clean VUE
var templateProductJson = new
{
//NOTE: name not working if dangurous characthers
//Name = System.Web.HttpUtility.HtmlEncode(product.GetString("Ecom:Product.Name")).Replace("\"", "'"),
Number = string.Format("[{0}]", product.GetString("Ecom:Product.Number")),
};
<div v-fbq-track.addtocart='@JsonConvert.SerializeObject(templateProductJson)'>
@RenderBuyButton(product.GetString("Ecom:Product.ID"), renderType)
</div>
}
@helper RenderBuyButton(string productKey, string renderType)
{
var redirectLinkIsNotAllowed = "?restrict=true";
var btn_addText = Translate("Add to cart", "Add to cart");
//TODO: change to setting under website settings
var isInternational = ObjectFactory.GetInstance<ContextService>().GetLanguageId().ToUpper().Equals("LANG2");
<ordering-list-request-product-condition product-key='@productKey' inline-template>
<div class="">
<template v-if="loading">
<div class="loading">
<span class="spinner-sm-default"></span>
</div>
</template>
<div v-show="!loading && (!isRestricted || isAvailable)" class="json-buy-btn">
@if (isInternational && !Pageview.User.LoggedIn)
{
if (renderType.Equals("grid"))
{
<a href="@redirectLinkIsNotAllowed" class="btn btn-primary btn-block btn-air" title="@btn_addText">
<span class="product-added-text">@btn_addText<i class="pe-is-ec-cart-1-f hide" aria-hidden="true"></i></span>
</a>
}
else if (renderType.Equals("table"))
{
<a href="@redirectLinkIsNotAllowed" class="btn btn-primary" title="@btn_addText">
<span class="product-added-text"><i class="pe-is-ec-cart-1-f" aria-hidden="true"></i></span>
</a>
}
else if (renderType.Equals("PDP"))
{
<a href="@redirectLinkIsNotAllowed" class="btn btn-primary btn-block">
<span class="product-added-text">@btn_addText</span>
</a>
}
}
else
{
if (renderType.Equals("grid"))
{
<button role="button" type="submit" class="btn btn-primary btn-block btn-air" title="@btn_addText">
<span class="product-added-text">@btn_addText<i class="pe-is-ec-cart-1-f hide" aria-hidden="true"></i></span>
</button>
}
else if (renderType.Equals("table"))
{
<div class="input-group">
<input name="quantity" value="1" type="tel" class="form-control text-center qty-input-manual" autocomplete="off" data-trigger="focus" data-rule-number="true" data-rule-min="1" :disabled="isRestricted && !isAvailable" />
<span class="input-group-btn">
<button role="button" type="submit" class="btn btn-primary ajax-add-to-cart" title="@btn_addText">
<span class="product-added-text"><i class="pe-is-ec-cart-1-f" aria-hidden="true"></i></span>
</button>
</span>
</div>
}
else if (renderType.Equals("PDP"))
{
<button class="btn btn-primary btn-block" role="button" type="submit">
<span class="product-added-text">@btn_addText</span>
</button>
}
}
</div>
<template v-if="!loading && (isRestricted && !isAvailable)">
<ordering-list-request-product :product-key='productKey'></ordering-list-request-product>
</template>
</div>
</ordering-list-request-product-condition>
}
<script type="text/x-template" id="ordering-list-request-product-template" v-pre>
<div>
<template v-if="loading">
<div class="loading">
<span class="spinner-sm-default"></span>
</div>
</template>
<template v-if="canRequestProduct && !loading">
<button class="btn btn-primary btn-block" role="button" type="button" v-on:click="requestProduct()" :disabled="isRequested">
<span v-if="!isRequested" class="product-added-text">@Translate("OrderingListRequestProductBtn", "Anmod om vare")</span>
<span v-if="isRequested" class="product-added-text">@Translate("OrderingListRequestProductBtn_isRequsted", "Anmoddet")</span>
</button>
</template>
</div>
</script>
@* ordering list request product - comments modal *@
@using StandardWebshop.CustomCode.Units.Models
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@helper RazorProductSupplementalPopup(UnitInformationViewModel unitInformation)
{
<table class="table table-condensed no-margin">
<tr>
<th class="text-left">@Translate("Product pakning", "Pakning")</th>
<th class="text-right">@Translate("Product indhold", "Indhold")</th>
</tr>
@{
foreach (var unit in unitInformation.SupplementalUnits.OrderByDescending(x => x.UnitCode.Equals("palle", StringComparison.InvariantCultureIgnoreCase)))
{
<tr>
<td class="text-left">1 @unit.UnitName</td>
@if (unit.UnitCode.Equals(unit.Bom))
{
<td class="text-right">@unit.BaseContentFactor @unit.BaseContentUOM</td>
}
else
{
<td class="text-right">@unit.QtyInBaseUnitOfMeasure @unit.Bom</td>
}
</tr>
}
}
</table>
}
@* Debugging: *@
@*<p>standard BOM : @productStandardBom.UnitName</p>
<p>defaultUnitid: @defaultUnitId</p>
<p>beforeprice : @beforePrice</p>*@
@{
var pdpProductJson = new
{
//NOTE: name not working if dangurous characthers
//Name = System.Web.HttpUtility.HtmlEncode(GetString("Ecom:Product.Name")),
Number = string.Format("[{0}]", GetString("Ecom:Product.Number")),
};
}
<p>@*@(JsonConvert.SerializeObject(productUnitInformation))*@</p>
<product-page inline-template>
<template>
<div class="col-xs-12">
<div v-show="loading">
<div class="loading">
<span class="spinner-xl-default"></span>
</div>
</div>
@* //temp track object - remove when converting to clean VUE *@
<div id="productPage-@GetString("Ecom:Product.Number")" v-visible="!loading" style="visibility: hidden; opacity: 0;" v-fbq-track.product='@JsonConvert.SerializeObject(pdpProductJson)'>
<section class="basic_pim js-product-scope" itemscope itemtype="http://schema.org/Product">
<div class="row @(!productScope_isSubstituteProduct ? "async-price" : "")" itemscope itemtype="http://schema.org/Product" data-product-key='@(this.GetJsonPriceKey())' data-product-retail-price='@(this.GetJsonRetailPrice())' data-product-unit-information='@JsonConvert.SerializeObject(productUnitInformation)'>
<div class="col-xs-12 col-sm-6 product-media">
@RenderProductLabels(isTilbud, isVolumePriceDiscount, productScope_discountedCompletely, productScope_discountedTemporary, isNewProduct, isOutlet, "PDP")
@if (specs.GetAllByKey("Image").Any())
{
<text>
@if (SpecImages.Any())
{
<div class="product-images" id="product-images">
@foreach (var images in SpecImages)
{
<a class="product-image mfp-image" data-image-type="image" href="/Admin/Public/GetImage.ashx?Width=1000&Height=1000&Crop=5&Compression=80&Image=/Files/Images/XPI/@(images.Value)">
<img itemprop="image" class="img-responsive" src="/Admin/Public/GetImage.ashx?Width=400&Height=400&Crop=5&Compression=80&Image=/Files/Images/XPI/@(images.Value)" alt="@System.Web.HttpUtility.HtmlEncode(GetString("Ecom:Product.Name"))" />
</a>
}
@foreach (var video in SpecVideos)
{
<a class="product-image mfp-iframe" data-image-type="video" href="http://www.youtube.com/watch?v=@(video.Value)?rel=0&autoplay=1">
<img itemprop="image" width="400" class="img-responsive" src="http://img.youtube.com/vi/@(video.Value)/0.jpg" />
</a>
}
</div>
if (SpecImages.Count() > 1 || SpecImages.Any() && SpecVideos.Any())
{
<div id="product-images-thumbs" class="product-thumbs">
@foreach (var images in SpecImages)
{
<div class="product-thumb">
<div class="product-thumb-inner" data-thumb-type="image">
<img class="img-responsive" src="/Admin/Public/GetImage.ashx?Width=110&Height=110&Crop=5&Compression=80&Image=/Files/Images/XPI/@(images.Value)" alt="@System.Web.HttpUtility.HtmlEncode(GetString("Ecom:Product.Name"))" />
</div>
</div>
}
@foreach (var video in SpecVideos)
{
<div class="product-thumb">
<div class="product-thumb-inner" data-thumb-type="video">
<img class="img-responsive" src="http://img.youtube.com/vi/@(video.Value)/1.jpg" alt="@System.Web.HttpUtility.HtmlEncode(GetString("Ecom:Product.Name"))" />
</div>
</div>
}
</div>
}
}
else
{
<div class="product-images">
<div class="product-image">
<div class="product-image-inner">
<img class="img-responsive" src="/Admin/Public/GetImage.ashx?&Width=400&Height=400&Crop=5&Compression=80&Image=/Files/Images/Ecom/default.png" alt="@Translate("No image","No image")" />
</div>
</div>
</div>
}</text>
}
else
{
<text>@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@if (image.GetImages().Any())
{
<div class="product-images" id="product-images">
@if (image.GetImages().Any())
{
foreach (var images in image.GetImages())
{
<a class="product-image mfp-zoom" href="/Admin/Public/GetImage.ashx?Width=1000&Height=1000&Crop=5&Compression=80&Image=@(images.Url)">
<img itemprop="image" class="img-responsive" src="/Admin/Public/GetImage.ashx?Width=400&Height=400&Crop=5&Compression=80&Image=@(images.Url)" alt="@System.Web.HttpUtility.HtmlEncode(GetString("Ecom:Product.Name"))" />
</a>
}
}
@if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.YoutubeVideoID")))
{
var YoutubeSrc = "https://www.youtube-nocookie.com/embed/" + GetString("Ecom:Product:Field.YoutubeVideoID") + "?rel=0";
<div class="product-image">
<iframe src="@YoutubeSrc" width="640" height="360" frameborder="0" allowfullscreen></iframe>
</div>
}
@if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.VimeoVideoID")))
{
var VimeoSrc = "https://player.vimeo.com/video/" + GetString("Ecom:Product:Field.VimeoVideoID") + "?byline=0";
<div class="product-image">
<iframe src="@VimeoSrc" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>
}
</div>
<div id="product-images-thumbs" class="product-thumbs">
@if (image.GetImages().Count() > 1 || image.GetImages().Any() && !String.IsNullOrEmpty(GetString("Ecom:Product:Field.YoutubeVideoID")) || !String.IsNullOrEmpty(GetString("Ecom:Product:Field.VimeoVideoID")))
{
foreach (var images in image.GetImages())
{
<div class="product-thumb">
<div class="product-thumb-inner" data-thumb-type="image">
<img class="img-responsive" src="/Admin/Public/GetImage.ashx?Width=110&Height=110&Crop=5&Compression=80&Image=@(images.Url)" alt="@System.Web.HttpUtility.HtmlEncode(GetString("Ecom:Product.Name"))" />
</div>
</div>
}
}
@if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.YoutubeVideoID")))
{
<div class="product-thumb">
<div class="product-thumb-inner" data-thumb-type="video">
<span class="product-thumb-play"><i class="icon-youtube icon-5x" aria-hidden="true"></i></span>
</div>
</div>
}
@if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.VimeoVideoID")))
{
<div class="product-thumb">
<div class="product-thumb-inner" data-thumb-type="video">
<span class="product-thumb-play"><i class="icon-vimeo icon-5x" aria-hidden="true"></i></span>
</div>
</div>
}
</div>
}
else
{
<div class="product-images">
<div class="product-image">
<div class="product-image-inner">
<img class="img-responsive" src="/Admin/Public/GetImage.ashx?Image=@(image.GetFirstImage().Url)&Width=400&Height=400&Crop=5&Compression=80" />
</div>
</div>
</div>
}</text>
}
</div>
<div class="col-xs-12 col-sm-6 product-data">
@if (specs.GetByKey("BrandSymbol") != null)
{
var brandSymbol = specs.GetByKey("BrandSymbol");
if (brandSymbol != null && !string.IsNullOrEmpty(brandSymbol.Value))
{
<div class="brand-logo">
<img src="/Admin/Public/GetImage.ashx?Width=225&Height=60&Compression=80&Crop=5&Image=/Files/Images/XPI/@brandSymbol.Value" alt="@brandSymbol.Value" class="img-responsive" />
</div>
}
}
<h1 itemprop="name" class="title-styled">
@System.Web.HttpUtility.HtmlEncode(GetString("Ecom:Product.Name"))
</h1>
<p class="print text-right">
<span class="product-id pull-left">
<i class="pe-is-ec-label-3-f pe-va"></i>
@Translate("Product Number", "Product Number"):
<span class="value" itemprop="sku">
@GetString("Ecom:Product.Number")
</span>
</span>
@* Fix this href so it uses the NORRIQ.SEO URL "NIQ:ProductUrl" *@
<a class="hidden-print" rel="nofollow" href="@Navigation.GetUrlByNavigationTag("productsheet")?ProductID=@GetString("Ecom:Product.ID")&VariantID=@GetString("Ecom:Product.VariantID")&PDF=true&Filename=@(GetString("Ecom:Product.Number")).pdf"><i class="pe-is-hs-printer-f" aria-hidden="true"></i> @Translate("Print PDF", "Print PDF")</a>
</p>
@if (!productScope_isSubstituteProduct)
{
<div class="product-price text-right" itemprop="offers" itemscope="" itemtype="http://schema.org/Offer">
@* Pricing *@
@* Volume prices *@
@if (isVolumePriceDiscount)
{
<div class="pricing indent">
@* <-- add class 'indent' when user is anonymous*@
<div class="table-responsive">
<table class="table table-condensed volume-table async-price-volumenpriser">
<tbody>
@foreach (var volumenpris in volumenpriser.Priser)
{
<tr>
@if (volumenpris.TranslatedUnitCaption.Equals(volumenpriser.BaseUnit))
{
<td class="text-left">@volumenpris.MinimumQuantity x @volumenpris.TranslatedUnitCaption</td>
}
else
{
<td class="text-left">@volumenpris.MinimumQuantity @volumenpris.TranslatedUnitCaption (@volumenpris.MinimumQuantityInBaseUnit @volumenpriser.BaseUnit)</td>
}
@if (Pageview.User.LoggedIn)
{
<td class="text-right">
@volumenpriser.BaseUnit
<span class="async-price-total" data-price-mode="details">
<i class="spinner-sm-default"></i>
</span>
</td>
}
else
{
<td class="text-right">@Translate("Volume Per", "pr.") @volumenpriser.BaseUnit @volumenpris.GetConvertedBOMPrice().ToString("N") @volumenpris.ConvertToCurrencyCode</td>
}
</tr>
}
</tbody>
</table>
</div>
</div>
}
@if (Pageview.User.LoggedIn && !hidePrices)
{
<div class="pricing">
<table class="table table-condensed pricing-table no-margin">
<thead>
<tr>
<th class="text-left"></th>
<th class="text-right js-hide-before" data-show-on-before-price="true">@Translate("NormalPrice", "Normalpris")</th>
<th class="text-right js-hide-before font-color-red">@Translate("Discount", "Rabat")</th>
<th class="text-right">@Translate("YourPrice", "Din pris")</th>
</tr>
</thead>
<tbody>
@foreach (var unit in units)
{
var supUnit = unit.SupplementalUnit;
<tr class="async-price" data-product-key='@(this.GetJsonPriceKey(unit.UnitId))' data-product-retail-price='@(this.GetJsonRetailPrice(unit.UnitId))'>
@if (unit.UnitName.Equals(supUnit.Bom))
{
bool showSupplementalInfo = supUnit.BaseContentFactor > 0 && !string.IsNullOrEmpty(supUnit.BaseContentUOM);
<td class="text-left">1 @unit.UnitName @(showSupplementalInfo ? string.Format("({0} {1})", @supUnit.BaseContentFactor, @supUnit.BaseContentUOM): "") </td>
}
else
{
<td class="text-left">1 @unit.UnitName (@supUnit.QtyInBaseUnitOfMeasure @supUnit.Bom) </td>
}
<td class="text-right font-striked">
<span class="js-hide-before" data-show-on-before-price="true">
<span class="async-price-unit" data-price-mode="details">
<i class="spinner-sm-default"></i>
</span>
</span>
</td>
<td class="text-right font-l font-color-red">
<span class="js-hide-before">
<span class="async-price-discount font-color-red" data-price-mode="details">
<i class="spinner-sm-default"></i>
</span>
</span>
</td>
<td class="text-right font-l">
<span>
<span class="async-price-total" itemprop="price" content="@pricePForGoogle" data-price-mode="details">
<i class="spinner-sm-default"></i>
</span>
</span>
</td>
</tr>
}
@*Clone this *@
<tr id="async-price-baseunitOUM-template" data-informative-unit-price="" style="display:none; visibility:hidden">
<td class="text-left">1 <span class="async-price-baseunitOUM"></span></td>
<td class="text-right font-striked">
<span data-show-on-before-price="true">
<span class="async-price-unit" data-price-mode="details">
<i class="spinner-sm-default"></i>
</span>
</span>
</td>
<td class="text-right font-l font-color-red">
@*<span class="js-hide-before">
<span class="async-price-discount font-color-red" data-price-mode="details">
<i class="spinner-sm-default"></i>
</span>
</span>*@
</td>
<td class="text-right font-l">
<span>
<span class="async-price-total" data-price-mode="details">
<i class="spinner-sm-default"></i>
</span>
</span>
</td>
</tr>
</tbody>
@if (packingSpec != null)
{
<tfoot>
<tr>
<td class="text-left" colspan="5">@Translate("ReMarks", "Bemærkninger:") @packingSpec.Value</td>
</tr>
</tfoot>
}
</table>
</div>
}
else if (!hidePrices)
{
<div class="pricing indent">
</div>
}
@* Product Fees *@
@* Ifølge Emnelog ID 39 er der kun gebyrer på den danske shop. *@
@* Fee are outcommented from PDP on request from anthony *@
@*
@if (Dynamicweb.Frontend.PageView.Current().AreaID == 1 && productFees.HasFees() && productFees.IsValid())
{
<div class="text-right">
<ul class="list-unstyled js-fee-container">
@foreach (var fee in productFees.Fees)
{
var skipFee = !units.Select(u => u.UnitId).Contains(fee.UnitCode);
if (skipFee)
{
continue;
}
var unit = units.FirstOrDefault(u => string.Equals(u.UnitId, fee.UnitCode));
var unitLabel = unit != null ? unit.UnitName : fee.UnitCode;
<li data-fee-unit-key="@fee.UnitCode">@fee.Description @fee.GetConvertedFeePrice().ToString("N") @fee.GetDisplayCurrency() / @unitLabel</li>
}
</ul>
</div>
}
*@
</div>
<div class="product-info hidden-print">
<form class="form-horizontal form-product clearfix" id="prodform_@GetString("Ecom:Product:Page.ID")" name="prodform_@GetString("Ecom:Product:Page.ID")" method="post" action="@GetGlobalValue("Global:Pageview.Url.Raw")">
@*
Because of DW and their use of Default units, we have to do this the manual way:
http://doc.dynamicweb.com/documentation-8/ecommerce/product-catalog/products#sideNavTitle1-2-5-4
The ones commented out has been deemed not necessary.
*@
@*@GetString("Ecom:Product.Form.Clean")*@
@*<input type="hidden" name="ProductURL" id="ProductURL" value="" />*@
<input type="hidden" name="CartCmd" value="add" />
<input type="hidden" name="ProductID" value="@(GetString("Ecom:Product.ID"))" />
<input type="hidden" name="VariantID" value="" />
@*<input type="hidden" name="UnitID" id="UnitID" value="STK" />*@
@*<input type="hidden" name="wishListID" id="wishListID" value="0" />*@
<label for="quantity" class="sr-only">@Translate("Qty", "Qty")</label>
<div class="form-group">
<div class="col-sm-4">
<ordering-list-request-product-condition product-key='@GetString("Ecom:Product.ID")' inline-template>
<div class="">
<template v-if="loading">
<div class="loading">
<span class="spinner-sm-default"></span>
</div>
</template>
<template v-if="!loading">
<div class="input-group">
<div class="input-group-addon">
@Translate("Product antal", "Antal")
</div>
<input name="quantity" value="1" min="1" type="number" class="form-control form-control-qty text-center" autocomplete="off" :disabled="isRestricted && !isAvailable" />
</div>
</template>
</div>
</ordering-list-request-product-condition>
</div>
<div class="col-sm-4">
<div class="popover-trigger">
<select name="UnitId" id="unitIdSelector" class="form-control form-unit unit-input JS-ASYNC-UNITSELECTOR JS-ASYNC-INPUT-VALUE" @(units.Count() <= 1 ? "readonly" : "")
data-trigger-async-price="false">
@foreach (var unit in units)
{
<option value="@unit.UnitId" @(String.Equals(unit.UnitId, defaultUnitId) ? "selected" : "")>@unit.UnitName</option>
}
</select>
</div>
<div class="hide my-popover-content">
@RazorProductSupplementalPopup(productUnitInformation)
</div>
</div>
<div class="col-sm-4">
@if (Pageview.User.LoggedIn)
{
<div class="product-button">
@RenderBuyButton(this, "PDP")
</div>
}
else
{
<p>
@Translate("product_view_loginToPurchase", "Log ind for at købe varen")
</p>
}
</div>
</div>
</form>
<div class="row">
@* Stocks *@
@* Stocks bliver hele tiden opdateret via asynkrone kald pga. at units og produktliste bliver loadet, derfor behøver vi ikke dette til at vise rigtig stocks. *@
@if (Pageview.User.LoggedIn)
{
<div class="col-xs-6 async-price" data-product-key='@(this.GetJsonPriceKey())' data-product-retail-price='@(this.GetJsonRetailPrice())'>
<span class="async-price-stock">
<i class="spinner-sm-default"></i>
</span>
</div>
}
else
{
<div class="col-xs-6">
@{
var stock = GetDouble("Ecom:Product.Stock");
var isStykliste = GetBoolean("Ecom:Product:Field.Stykliste.Value");
var isSkaffevare = GetBoolean("Ecom:Product:Field.Skaffevare.Value");
}
@if (isSkaffevare && stock == 0)
{
<i class="icon-stock icon-blue" title="@Translate("label_skaffevare", "Skaffevare")"></i>
<span class="stock-label-text">@Translate("label_skaffevare", "Skaffevare")</span>
}
else
{
if (stock < 1 && !isStykliste)
{
<i class="icon-stock icon-yellow" title="@Translate("label_in_stock_in_x_days", "Forventes på lager indenfor 4 dage.")"></i>
<span class="stock-label-text">@Translate("label_in_stock_in_x_days", "Forventes på lager indenfor 4 dage.")</span>
}
else
{
<i class="icon-stock icon-green" title="@stock"></i>
if (isOutlet)
{
<span class="stock-label-text">@stock @Translate("label_in_stock", "In stock")</span>
}
else
{
<span class="stock-label-text">@Translate("label_in_stock", "In stock")</span>
}
}
}
</div>
}
@* Favoritelist *@
@if (Pageview.User.LoggedIn)
{
<div class="col-xs-6 text-right hidden-print">
@RenderFavoriteListIcon(this)
</div>
}
</div>
</div>
<text>@using NLWI.Platforms.Dynamicweb8.Specs;
@using NLWI.Platforms.Dynamicweb8.Specs.ViewModels
@using StandardWebshop.CustomCode.ColorLookup
@using StandardWebshop.CustomCode.Razor
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@{
var specsRef = ((ProductSpecifications)specs);
var databladeFiles = new List<ProductSpecification>();
var listOfDataBladeKey = new List<string>
{
"Datablade",
"EnvironmentDocs",
"DeclarationOfConformity",
"SparePartsCatalogue",
"UserGuide",
"SafetyDatasheet",
"SizeGuide"
};
foreach (var key in listOfDataBladeKey)
{
var currentDataBlade = specsRef.GetAllByKey(key);
databladeFiles.AddRange(currentDataBlade);
}
//var specs = this.GetProductSpecifications();
var showDescription = !String.IsNullOrWhiteSpace(GetString("Ecom:Product.LongDescription")) || !String.IsNullOrEmpty(specsRef.GetByKey("Produktbeskrivelse").Value);
var showTabs = showDescription || specsRef.GetByGroup("Specifikationer").Any() || databladeFiles.Any();
var colorLookupService = ObjectFactory.GetInstance<ColorLookupService>();
}
@if (showTabs)
{
<ul class="nav nav-tabs product-nav-tabs" role="tablist">
@if (showDescription)
{
<li role="presentation" class="active">
<a href="#desc" aria-controls="desc" role="tab" data-toggle="tab">
@Translate("Description", "Description")
</a>
</li>
}
@if (specsRef.GetByGroup("Specifikationer").Any())
{
<li role="presentation" class="@(!showDescription ? "active": "")">
<a href="#specs" aria-controls="specs" role="tab" data-toggle="tab">
@Translate("Specifications", "Specifications")
</a>
</li>
}
@if (databladeFiles.Any())
{
<li role="presentation" class="@(!showDescription && !specsRef.GetByGroup("Specifikationer").Any() ? "active": "")">
<a href="#docs" aria-controls="docs" role="tab" data-toggle="tab">
@Translate("Documents", "Documents")
</a>
</li>
}
</ul>
<div class="tab-content product-tab-content">
@if (showDescription)
{
<div role="tabpanel" class="tab-pane active" id="desc" itemprop="description">
@specsRef.GetByKey("Produktbeskrivelse").Value
</div>
}
@if (specsRef.GetByGroup("Specifikationer").Any())
{
<div role="tabpanel" class="tab-pane @(!showDescription ? "active": "")" id="specs">
@RenderSpecifications(specsRef, "table", "BrandSymbol")
</div>
}
@if (databladeFiles.Any())
{
<div role="tabpanel" class="tab-pane @(!showDescription && !specsRef.GetByGroup("Specifikationer").Any() ? "active": "")" id="docs">
<ul class="list-unstyled">
@foreach (var specFile in databladeFiles)
{
var originalFilename = specFile.GetReferenceSpecification().GetByKey("Filename").Value;
var title = originalFilename.Replace("_", " ").Replace("-", " ");
<li>
<a download="@originalFilename" href="/Files/XPI-Files/@(specFile.Value)" title="@originalFilename">
@specFile.Caption
</a>
</li>
}
</ul>
</div>
}
</div>
}
</text>
//end isSubstitute product statement
}
else
{
//if the product is a substitution product render this section instead.
//This way to scope the feature is much easier to maintain changes in the future
<div class="substitute-information-wrapper">
<p class="print">
@if (productScope_discountedCompletely)
{
@Translate("product_view_discountedCompletelyProductSection", "Denne vare er udgået af vores sortiment.")
}
else if (productScope_discountedTemporary)
{
@Translate("product_view_discountedTemporaryProductSection", "Denne vare er midlertidig udgået.")
}
else
{
//NOT SUPPORTED..
}
</p>
</div>
<text>@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@{
Columns = "col-md-8";
}
@if (GetLoop("ProductRelatedGroups").Any())
{
foreach (var grp in GetLoop("ProductRelatedGroups"))
{
if (!grp.GetString("Ecom:Product:RelatedGroup.GroupID").Equals("RELGRP3"))
{
//Skip if this is NOT RELGRP3
continue;
}
if (grp.GetLoop("RelatedProducts").Where(x => !x.GetBoolean("NIQ:Product.PRIVATE")).Any())
{
//TODO: add substitute products to all languages
<h2 class="title-styled">
@grp.GetString("Ecom:Product:RelatedGroup.Name")
</h2>
<div class="productlist-grid-flex" id="[email protected]("Ecom:Product:RelatedGroup.GroupID")">
@{
var substituteProductList = grp.GetLoop("RelatedProducts").Where(x => !x.GetBoolean("NIQ:Product.PRIVATE"));
}
@foreach (var product in substituteProductList)
{
<text>@using System.Globalization
@using System.Web.Mvc.Html
@using Dynamicweb.NewsLetterV3
@using NORRIQ.EcomMedia
@using StandardWebshop.CustomCode.Razor
@using NORRIQ.Common8.Razor;
@using NORRIQ.Common8.Factory
@using Newtonsoft.Json
@using Dynamicweb.eCommerce.Common;
@using Dynamicweb.eCommerce.Products
@using StandardWebshop.CustomCode.SupplementalUnit
@using StandardWebshop.CustomCode.ViewModels.Variants;
@using StandardWebshop.CustomCode.Volumenpriser
@using StandardWebshop.CustomCode.Units;
@using StandardWebshop.CustomCode.Units.Models
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@{
var currentUser = Dynamicweb.Modules.UserManagement.User.GetCurrentUser();
var hidePrice = false;
if (currentUser != null)
{
hidePrice = currentUser.CustomFieldValues.FirstOrDefault(cf => cf.CustomField.SystemName == "AccessUser_HidePrices").Value.ToString().ToLower() == "true" ? true : false;
}
//this is required do to lazy loading
//product.GetLoop("Units").Select(u => new
//{
// UnitId = u.GetString("Ecom:VariantOption.ID"),
// // Change the number format here:
// UnitPriceDouble = (u.GetDouble("Ecom:VariantOption.Price.PricePIP") / 100d),
// UnitName = u.GetString("Ecom:VariantOption.Name"),
// UnitObj = u
//}).OrderBy(x => x.UnitPriceDouble);
var link = product.GetString("NIQ:ProductUrl");
var tilbud = product.GetBoolean("Ecom:Product:Field.Tilbud.Value");
var buy = "/default.aspx?ID=" + Navigation.GetPageIdByNavigationTag("ecom") + "&productid=" + product.GetString("Ecom:Product.ID") + "&cartcmd=add";
var area = GetGlobalValue("Global:Area.Lang");
var media = NORRIQ.EcomMedia.Frontend.GetProductMedia(product);
var ProductSpecs = product.GetProductSpecifications();
var Image = ProductSpecs.GetAllByKey("Image").Any() ? "/Files/Images/XPI/" + ProductSpecs.GetByKey("Image").Value : media.GetFirstImage().Url;
var isLoggedIn = Pageview.User.LoggedIn;
var priceForGoogle = product.GetString("NIQ:PriceForGoogle");
var btn_addText = Translate("Add to cart", "Add to cart");
// Units
var unitInformation = product.GetUnitInformation() as UnitInformationViewModel;
var productListUnits = unitInformation.Units;
var productListDefaultUnit = unitInformation.ProductDefaultUnit;
//volumenPrices
var productgridVolumenpriser = product.GetVolumenpriser();
bool discountedCompletely = product.GetBoolean("NIQ:Product.DiscontunedCompletely");
bool discountedTemporary = product.GetBoolean("NIQ:Product.DiscontunedTemporary");
bool isSubstituteProduct = discountedTemporary || discountedCompletely;
string substituteProductID = product.GetString("NIQ:Product.SubstituteProductId");
string subStituteLink = string.Empty;
if (isSubstituteProduct && substituteProductID != null)
{
subStituteLink = string.Format("/Default.aspx?ID={0}&productID={1}", NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("ecom"), substituteProductID);
}
tilbud = tilbud || productListUnits.Any(x => x.IsInformativePrice);
var productGridIsVolumenDiscount = productgridVolumenpriser.HasPrices() && productgridVolumenpriser.IsValid();
}
@if (productListDefaultUnit != null)
{
<product product-key="@product.GetString("Ecom:Product.ID")" inline-template>
<template>
<div v-bind:class="{hide: hide, fadeout : fadeout}" class="product-wrapper @Columns @(!isSubstituteProduct ? "async-price " : "" ) js-favProduct" data-product-display="flex" data-product-key-clean='@(product.GetString("Ecom:Product.ID"))' data-product-key='@(product.GetJsonPriceKey((string)productListDefaultUnit.UnitId))' data-product-retail-price='@(product.GetJsonRetailPrice())' data-product-unit-information='@JsonConvert.SerializeObject(unitInformation)'>
<div itemscope itemtype="http://schema.org/Product" class="productlist-grid-product">
@{
var isNyhed = product.GetBoolean("Ecom:Product:Field.Nyhed.Value");
var isOutle = product.GetBoolean("Ecom:Product:Field.Outlet.Value");
}
@RenderProductLabels(tilbud, productGridIsVolumenDiscount, discountedCompletely, discountedTemporary, isNyhed, isOutle)
<a class="productlist-grid-image" href="@link" itemprop="url">
<img src="/Admin/Public/GetImage.ashx?Width=200&Height=200&Crop=5&Compression=80&Image=@Image"
class="img-responsive" alt="@System.Web.HttpUtility.HtmlEncode(product.GetString("Ecom:Product.Name"))" itemprop="image" />
</a>
<div class="productlist-grid-caption">
<a href="@link" class="productlist-grid-name" itemprop="name">
@System.Web.HttpUtility.HtmlEncode(product.GetString("Ecom:Product.Name"))
</a>
</div>
<div class="offer" itemprop="offers" itemscope="" itemtype="http://schema.org/Offer">
@if (!isSubstituteProduct)
{
<div class="productlist-grid-info">
<span class="productlist-grid-number">
@Translate("Product Number", "Product Number") <span itemprop="sku">@product.GetString("Ecom:Product.Number")</span>
</span>
<span class="productlist-grid-stock">
@if (Pageview.User.LoggedIn)
{
<span class="async-price-stock" itemprop="availability">
<span class="spinner-sm-default"></span>
</span>
}
else
{
@RenderStockInformations(product)
}
</span>
</div>
<div class="productlist-grid-footer">
<div class="productlist-grid-price-info">
<div class="productlist-grid-price js-price-container">
@if (Pageview.User.LoggedIn && !hidePrice)
{
<span class="async-price-unit"></span>
<span class="productlist-grid-price-price async-price-total" itemprop="price"></span>
}
</div>
</div>
@if (ObjectFactory.GetInstance<NORRIQ.Common8.Context.AreaItemSettings>().GetCurrentAreaValue<string>("ProductlistGridHideButton") == "False")
{
<div class="productlist-grid-buying">
@if (product.GetLoop("VariantGroups").Any())
{
<a href="@link" class="btn btn-buy">
<span class="product-added-text">@Translate("Buy", "Buy")</span>
</a>
}
else
{
<form class="form" id="[email protected]("Ecom:Product.ID")" name="[email protected]("Ecom:Product.ID")" method="post" action="/Default.aspx?ID=@GetGlobalValue("Global:Page.ID")">
@*
Because of DW and their use of Default units, we have to do this the manual way:
http://doc.dynamicweb.com/documentation-8/ecommerce/product-catalog/products#sideNavTitle1-2-5-4
The ones commented out has been deemed not necessary.
*@
@*@GetString("Ecom:Product.Form.Clean")*@
@*<input type="hidden" name="ProductURL" id="ProductURL" value="" />*@
<input type="hidden" name="CartCmd" value="add" />
<input type="hidden" name="ProductID" value="@(product.GetString("Ecom:Product.ID"))" />
<input type="hidden" name="VariantID" value="" />
@*<input type="hidden" name="UnitID" id="UnitID" value="STK" />*@
@*<input type="hidden" name="wishListID" id="wishListID" value="0" />*@
@{
}
<ordering-list-request-product-condition product-key='@product.GetString("Ecom:Product.ID")' inline-template>
<div class="">
<template v-if="loading">
<div class="loading">
<span class="spinner-sm-default"></span>
</div>
</template>
<div v-show="!loading" class="input-group popover-trigger">
<input name="quantity" value="1" min="1" max="99999" type="number" class="form-control text-center" autocomplete="off" data-trigger="focus" data-rule-number="true" data-rule-min="1" :disabled="isRestricted && !isAvailable" />
<span class="input-group-btn">
<select name="UnitId" class="form-control form-unit unit-input JS-ASYNC-UNITSELECTOR JS-ASYNC-INPUT-VALUE" @(productListUnits.Count() <= 1 ? "readonly" : "")>
@foreach (var unit in productListUnits)
{
<option value="@unit.UnitId" @(String.Equals(unit.UnitId, productListDefaultUnit.UnitId) ? "selected" : "")>@unit.UnitName</option>
}
</select>
</span>
</div>
<div class="hide my-popover-content">
@RazorProductSupplementalPopup(unitInformation)
</div>
</div>
</ordering-list-request-product-condition>
@if (Pageview.User.LoggedIn)
{
@RenderBuyButton(product, "grid")
}
</form>
}
</div>
}
</div>
}
else
{
//if the product is a substitution product render this section instead.
//This way to scope the feature is much easier to maintain changes in the future
<div class="productlist-grid-info">
<span class="productlist-grid-number">
@Translate("Product Number", "Product Number") <span itemprop="sku">@product.GetString("Ecom:Product.Number")</span>
</span>
<span class="productlist-grid-stock">
@RenderStockInformations(product, true)
</span>
</div>
<a class="btn btn-primary btn-block btn-air" href="@subStituteLink">@Translate("erstatningsvare")</a>
}
</div>
@if (isLoggedIn && !product.GetLoop("VariantGroups").Any())
{
<div class="productlist-grid-buttons">
@RenderFavoriteListIcon(product)
</div>
}
</div>
</div>
</template>
</product>
}
</text>
}
</div>
}
}
}</text>
}
</div>
</div>
</section>
<div class="col-xs-12">
<div class="row">
<div class="col-xs-12 product-related hidden-print">
@using System.Globalization
@using System.Web.Mvc.Html
@using Dynamicweb.NewsLetterV3
@using NORRIQ.EcomMedia
@using StandardWebshop.CustomCode.Razor
@using NORRIQ.Common8.Razor;
@using NORRIQ.Common8.Factory
@using Dynamicweb.eCommerce.Common;
@using Newtonsoft.Json
@using StandardWebshop.CustomCode.ViewModels.Variants;
@using NLWI.Platforms.Dynamicweb8.Specs
@using StandardWebshop.CustomCode.ColorLookup
@using StandardWebshop.CustomCode.Razor
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@if (GetLoop("ProductRelatedGroups").Any())
{
foreach (var grp in GetLoop("ProductRelatedGroups"))
{
if (grp.GetString("Ecom:Product:RelatedGroup.GroupID").Equals("RELGRP2"))
{
<h2 class="title-styled">
@grp.GetString("Ecom:Product:RelatedGroup.Name")
</h2>
var productsBinding = grp.GetLoop("RelatedProducts").Where(x => !x.GetBoolean("NIQ:Product.PRIVATE"));
tableModeBinding = "variants";
<text>@using System.Globalization
@using System.Web.Mvc.Html
@using Dynamicweb.NewsLetterV3
@using NORRIQ.EcomMedia
@using StandardWebshop.CustomCode.Razor
@using NORRIQ.Common8.Razor;
@using NORRIQ.Common8.Factory
@using Newtonsoft.Json
@using Dynamicweb.eCommerce.Common;
@using NLWI.Platforms.Dynamicweb8.Specs
@using StandardWebshop.CustomCode.ColorLookup
@using StandardWebshop.CustomCode.SupplementalUnit
@using StandardWebshop.CustomCode.Units.Models
@using StandardWebshop.CustomCode.ViewModels.Variants;
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@{
var tableUser = Dynamicweb.Modules.UserManagement.User.GetCurrentUser();
var hidePriceinTableView = false;
if (tableUser != null)
{
hidePriceinTableView = tableUser.CustomFieldValues.FirstOrDefault(cf => cf.CustomField.SystemName == "AccessUser_HidePrices").Value.ToString().ToLower() == "true" ? true : false;
}
var addToCartMode = ObjectFactory.GetInstance<NORRIQ.Common8.Context.AreaItemSettings>().GetCurrentAreaValue<string>("AddToCartMode");
var colorLookupService2 = ObjectFactory.GetInstance<ColorLookupService>();
var isLoggedIn = Pageview.User.LoggedIn;
var products = productsBinding;
if (products == null)
{
throw new Exception("product table binding reference is not set!");
}
string tableMode = tableModeBinding;
}
<table class="table table-striped table-block productlist-table js-product-table">
<thead>
<template v-if="!loading">
<tr>
<th class="visible-printxx"></th>
<th class="productlist-table-product">
@Translate("Product", "Product")
</th>
@*start Variant headers*@
<th class="productlist-table-variant">@*Description: variant size*@</th>
<th class="productlist-table-variant">@*Description: variant color*@</th>
@*end Variant headers*@
<th class="productlist-table-number" nowrap>
@Translate("Product Number", "Product Number")
</th>
<th class="productlist-table-stock" nowrap>
@Translate("Stock", "Stock")
</th>
@if (isLoggedIn)
{
<th class="productlist-table-favorite">
@if (isFavoriteList)
{
<orderinglist-filter></orderinglist-filter>
}
@*<i class="icon-favorite-added" aria-hidden="true"></i><span class="sr-only">@Translate("Favorite", "Favorite")</span>*@
</th>
}
@if (!hidePriceinTableView)
{
<th class="productlist-table-price">
@Translate("Price", "Price")
</th>
}
<th>
@Translate("Unit", "Unit")
</th>
<th class="productlist-table-quantity">
@Translate("Quantity", "Quantity")
</th>
</tr>
</template>
</thead>
<tbody>
@foreach (var product in products)
{
var tilbud = product.GetBoolean("Ecom:Product:Field.Tilbud.Value");
var LoopCounter = product.GetInteger("Ecom:Product.LoopCounter") - 1;
var media = NORRIQ.EcomMedia.Frontend.GetProductMedia(product);
var link = product.GetString("NIQ:ProductUrl");
var area = GetGlobalValue("Global:Area.Lang");
var productSpecs = product.GetProductSpecifications();
var Image = productSpecs.GetAllByKey("Image").Any() ? "/Files/Images/XPI/" + productSpecs.GetByKey("Image").Value : media.GetFirstImage().Url;
var variants = product.GetLoop("VariantGroups").GetVariants();
// In IBH, the Product Number can be used as a unique product identifier.
var currentProductNumber = product.GetString("Ecom:Product.Number");
// All variant products and their associated variant groups/options.
var variantProducts = product.GetLoop("VariantCombinations").GetVariantProducts(variants, currentProductNumber);
var productsDictionary = VariantViewModelBuilder.GetProductsInDimensionOrder(variants, variantProducts);
var selectedVariant = VariantViewModelBuilder.GetSelectedOrEmpty(variantProducts);
//variants
var productSpecGroup = productSpecs.GetByGroup("Specifikationer");
//custom size names
IEnumerable<string> filterSizeKeys = new List<string>
{
"specs_Handskestorrelse",
"specs_Toejstoerrelse",
"specs_Skostoerrelse",
"specs_Stoerrelse"
};
//remove prefix "specs_"
filterSizeKeys = filterSizeKeys.Select(s => s.Replace("specs_", ""));
var sizeObj = productSpecs.FirstOrDefault(x => filterSizeKeys.Any(s => s.Equals(x.Key)) && !string.IsNullOrEmpty(x.Value));
var colorList = productSpecGroup.Where(x => x.Key.Equals("Farve") && !string.IsNullOrEmpty(x.Value));
//end variants
bool discountedCompletely = product.GetBoolean("NIQ:Product.DiscontunedCompletely");
bool discountedTemporary = product.GetBoolean("NIQ:Product.DiscontunedTemporary");
bool isSubstituteProduct = discountedTemporary || discountedCompletely;
string substituteProductID = product.GetString("NIQ:Product.SubstituteProductId");
string subStituteLink = string.Empty;
if (isSubstituteProduct && substituteProductID != null)
{
subStituteLink = string.Format("/Default.aspx?ID={0}&productID={1}", NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("ecom"), substituteProductID);
}
// Units
var unitInformation = product.GetUnitInformation() as UnitInformationViewModel;
var productListUnits = unitInformation.Units;
var productListDefaultUnit = unitInformation.ProductDefaultUnit;
var listDefaultUnitId = productListDefaultUnit.UnitId;//;product.GetString("Ecom:Product.DefaultUnitID");
tilbud = tilbud || productListUnits.Any(x => x.IsInformativePrice);
var volumePrices = product.GetVolumenpriser();
var isVolumenDiscount = volumePrices.HasPrices() && volumePrices.IsValid();
@* These lines are required because lazy load's its data.
product.GetString("Ecom:VariantGroup.Label")
product.GetString("Ecom:VariantGroup.Name")
product.GetLoop("VariantAvailableOptions")
product.GetString("Ecom:VariantOption.ID")
product.GetString("Ecom:VariantOption.Name")
*@
<template>
<product product-key="@product.GetString("Ecom:Product.ID")" inline-template>
<template>
<tr @(Pageview.User.LoggedIn ? "v-bind:class='{hide: hide, fadeout : fadeout}'" : string.Empty) itemprop="offers" itemscope="" itemtype="http://schema.org/Offer" class="product-wrapper async-price js-favProduct" data-product-key-clean='@(product.GetString("Ecom:Product.ID"))' data-product-key='@(product.GetJsonPriceKey())' data-product-retail-price='@(product.GetJsonRetailPrice())' data-product-unit-information='@JsonConvert.SerializeObject(unitInformation)'>
<td align="left" width="50" class="visible-printxx">
@if (tableMode == "variants")
{
<div class="image-wrapper">
<img itemprop="image" class="img-responsive" src="/Admin/Public/GetImage.ashx?Width=400&Height=400&Crop=5&Compression=80&Image=@Image" />
</div>
}
else
{
//default
<img src="/Admin/Public/GetImage.ashx?Width=40&Height=35&Crop=5&Compression=85&Image=@Image" />
}
</td>
<td class="productlist-table-product">
@{
var isNyhed = product.GetBoolean("Ecom:Product:Field.Nyhed.Value");
var isOutle = product.GetBoolean("Ecom:Product:Field.Outlet.Value");
}
@RenderProductLabels(tilbud, isVolumenDiscount, discountedCompletely, discountedTemporary, isNyhed, isOutle)
<a href="@link" tabindex="0" class="productlist-table-name" itemprop="name">
@System.Web.HttpUtility.HtmlEncode(product.GetString("Ecom:Product.Name"))
</a>
</td>
@*start Variant rows*@
<td class="productlist-table-variant productlist-table-size">
<span>@(sizeObj != null ? sizeObj.Value : string.Empty)</span>
</td>
<td class="productlist-table-variant productlist-table-color">
@if (colorList.Any())
{
foreach (var colorObj in colorList)
{
var color = colorLookupService2.GetColorKey(colorObj.Value);
<span class="spec-color spec-color-@color"></span>
}
}
</td>
@*end Variant rows*@
<td class="productlist-table-number" itemid="sku" data-label="@Translate("Product No", "Product No")" nowrap>
@product.GetString("Ecom:Product.Number")
</td>
@if (isSubstituteProduct)
{
<td class="productlist-table-stock" itemprop="availability" href="http://schema.org/InStock" data-label="@Translate("Stock", "Stock")" nowrap>
@RenderStockInformations(product, isSubstituteProduct)
</td>
if (isLoggedIn)
{
<td data-label="Favorite">
@RenderFavoriteListIcon(product, "table")
</td>
}
<td class="productlist-table-price" nowrap="nowrap"></td>
<td></td>
<td class="productlist-table-variant">
<a class="btn btn-primary btn-block" href="@subStituteLink">@Translate("erstatningsvare")</a>
</td>
<td colspan="2">
<a class="btn btn-primary btn-block" href="@subStituteLink">@Translate("erstatningsvare")</a>
</td>
}
else
{
if (isLoggedIn)
{
<td class="productlist-table-stock async-price-stock" itemprop="availability" href="http://schema.org/InStock" data-label="@Translate("Stock", "Stock")" nowrap>
<i class="spinner-sm-default"></i>
</td>
}
else
{
<td class="productlist-table-stock" itemprop="availability" href="http://schema.org/InStock" data-label="@Translate("Stock", "Stock")" nowrap>
@RenderStockInformations(product, isSubstituteProduct)
</td>
}
if (isLoggedIn)
{
<td data-label="Favorite">
@RenderFavoriteListIcon(product, "table")
</td>
}
if (!hidePriceinTableView)
{
<td class="productlist-table-price js-price-container" nowrap="nowrap">
@if (isLoggedIn)
{
<span class="async-price-unit"></span>
<span class="productlist-table-price-price async-price-total" itemprop="price" data-label="@Translate("Price", "Price")">
<i class="spinner-sm-default" aria-hidden="true"></i>
</span>
}
else
{
var defaultUnit = productListUnits.FirstOrDefault(x => x.UnitId.Equals(listDefaultUnitId));
if (defaultUnit != null)
{
if (defaultUnit.IsInformativePrice)
{
<span class="product-price-before">@defaultUnit.UnitBeforePrice</span>
}
<span class="productlist-grid-price-price @(defaultUnit.IsInformativePrice ? "font-hilite" : string.Empty)" itemprop="price" content="@product.GetString("NIQ:PriceForGoogle")">
@defaultUnit.UnitPrice
<span itemprop="priceCurrency" content="@Context.Currency.Symbol">@Context.Currency.Symbol</span>
</span>
}
}
</td>
}
@* Units *@
<td>
<div class="popover-trigger">
<select name="UnitId" style="min-width: 80px;" class="form-control form-unit unit-input JS-ASYNC-UNITSELECTOR JS-ASYNC-INPUT-VALUE" @(productListUnits.Count() <= 1 ? "readonly" : "")>
@foreach (var unit in productListUnits)
{
<option value="@unit.UnitId" @(String.Equals(unit.UnitId, listDefaultUnitId) ? "selected" : "")>@unit.UnitName</option>
}
</select>
</div>
<div class="hide my-popover-content">
@RazorProductSupplementalPopup(unitInformation)
</div>
</td>
if (product.GetLoop("VariantGroups").Any())
{
<td class="productlist-table-variant">
<a href="@link" class="btn btn-buy"><i class="icon-minicart" aria-hidden="true"></i> <span class="sr-only">@Translate("Buy", "Buy")</span></a>
</td>
}
else
{
<td class="productlist-table-quantity">
@* For stadsing, we always have the "Single" add to cart. *@
@if (true || addToCartMode == "single")
{
<form class="form productlist-table-form" name="[email protected]("Ecom:Product.ID")" method="post" action="@GetGlobalValue("Global:Pageview.Url.Raw")">
@*
Because of DW and their use of Default units, we have to do this the manual way:
http://doc.dynamicweb.com/documentation-8/ecommerce/product-catalog/products#sideNavTitle1-2-5-4
The ones commented out has been deemed not necessary.
*@
@*@GetString("Ecom:Product.Form.Clean")*@
@*<input type="hidden" name="ProductURL" id="ProductURL" value="" />*@
<input type="hidden" name="CartCmd" value="add" />
<input type="hidden" name="ProductID" value="@(product.GetString("Ecom:Product.ID"))" />
<input type="hidden" name="VariantID" value="" />
@*<input type="hidden" name="UnitID" id="UnitID" value="STK" />*@
@*<input type="hidden" name="wishListID" id="wishListID" value="0" />*@
@if (Pageview.User.LoggedIn)
{
@RenderBuyButton(product, "table")
}
</form>
}
else
{
<input type="tel"
class="form-control qty-input text-center"
onclick="this.focus();this.select();"
name="Quantity@(LoopCounter)"
id="Quantity@(LoopCounter)"
value="@(product.GetInteger("NIQ:BasketQuantity"))"
data-product-autoid="@(product.GetInteger("NIQ:ProductAutoId"))"
data-tabindex="@(LoopCounter)"
data-trigger="manual" />
<span class="productlist-table-added btn btn-buy qty-input-user-feedback"
data-product-autoid="@(product.GetInteger("NIQ:ProductAutoId"))">
@if (product.GetInteger("NIQ:BasketQuantity") > 0)
{
<i class="icon-added"></i>
}
else
{
<i class="icon-minicart"></i>
}
</span>
}
</td>
}
}
</tr>
</template>
</product>
</template>
}
</tbody>
</table>
</text>
<hr class="spacer" />
}
}
}
<template>
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@{
// Related products
Columns = "col-xs-12 col-sm-4 col-md-4";
}
@if (GetLoop("ProductRelatedGroups").Any())
{
foreach (var grp in GetLoop("ProductRelatedGroups"))
{
if (grp.GetString("Ecom:Product:RelatedGroup.GroupID").Equals("RELGRP1"))
{
var relatedProductList = grp.GetLoop("RelatedProducts").Where(x => !x.GetBoolean("NIQ:Product.PRIVATE")).ToList();
if (relatedProductList.Any())
{
<header class="basic_related-header" id="related-header">
<h2 class="title-styled">
@grp.GetString("Ecom:Product:RelatedGroup.Name")
</h2>
</header>
if (relatedProductList.Count > 3)
{
<section class="basic_related">
<slick class="basic_related_slick"
ref="slick"
:options="slickRelatedOptions">
@foreach (var product in relatedProductList)
{
<template>
@using System.Globalization
@using System.Web.Mvc.Html
@using Dynamicweb.NewsLetterV3
@using NORRIQ.EcomMedia
@using StandardWebshop.CustomCode.Razor
@using NORRIQ.Common8.Razor;
@using NORRIQ.Common8.Factory
@using Newtonsoft.Json
@using Dynamicweb.eCommerce.Common;
@using Dynamicweb.eCommerce.Products
@using StandardWebshop.CustomCode.SupplementalUnit
@using StandardWebshop.CustomCode.ViewModels.Variants;
@using StandardWebshop.CustomCode.Volumenpriser
@using StandardWebshop.CustomCode.Units;
@using StandardWebshop.CustomCode.Units.Models
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@{
var currentUser = Dynamicweb.Modules.UserManagement.User.GetCurrentUser();
var hidePrice = false;
if (currentUser != null)
{
hidePrice = currentUser.CustomFieldValues.FirstOrDefault(cf => cf.CustomField.SystemName == "AccessUser_HidePrices").Value.ToString().ToLower() == "true" ? true : false;
}
//this is required do to lazy loading
//product.GetLoop("Units").Select(u => new
//{
// UnitId = u.GetString("Ecom:VariantOption.ID"),
// // Change the number format here:
// UnitPriceDouble = (u.GetDouble("Ecom:VariantOption.Price.PricePIP") / 100d),
// UnitName = u.GetString("Ecom:VariantOption.Name"),
// UnitObj = u
//}).OrderBy(x => x.UnitPriceDouble);
var link = product.GetString("NIQ:ProductUrl");
var tilbud = product.GetBoolean("Ecom:Product:Field.Tilbud.Value");
var buy = "/default.aspx?ID=" + Navigation.GetPageIdByNavigationTag("ecom") + "&productid=" + product.GetString("Ecom:Product.ID") + "&cartcmd=add";
var area = GetGlobalValue("Global:Area.Lang");
var media = NORRIQ.EcomMedia.Frontend.GetProductMedia(product);
var ProductSpecs = product.GetProductSpecifications();
var Image = ProductSpecs.GetAllByKey("Image").Any() ? "/Files/Images/XPI/" + ProductSpecs.GetByKey("Image").Value : media.GetFirstImage().Url;
var isLoggedIn = Pageview.User.LoggedIn;
var priceForGoogle = product.GetString("NIQ:PriceForGoogle");
var btn_addText = Translate("Add to cart", "Add to cart");
// Units
var unitInformation = product.GetUnitInformation() as UnitInformationViewModel;
var productListUnits = unitInformation.Units;
var productListDefaultUnit = unitInformation.ProductDefaultUnit;
//volumenPrices
var productgridVolumenpriser = product.GetVolumenpriser();
bool discountedCompletely = product.GetBoolean("NIQ:Product.DiscontunedCompletely");
bool discountedTemporary = product.GetBoolean("NIQ:Product.DiscontunedTemporary");
bool isSubstituteProduct = discountedTemporary || discountedCompletely;
string substituteProductID = product.GetString("NIQ:Product.SubstituteProductId");
string subStituteLink = string.Empty;
if (isSubstituteProduct && substituteProductID != null)
{
subStituteLink = string.Format("/Default.aspx?ID={0}&productID={1}", NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("ecom"), substituteProductID);
}
tilbud = tilbud || productListUnits.Any(x => x.IsInformativePrice);
var productGridIsVolumenDiscount = productgridVolumenpriser.HasPrices() && productgridVolumenpriser.IsValid();
}
@if (productListDefaultUnit != null)
{
<product product-key="@product.GetString("Ecom:Product.ID")" inline-template>
<template>
<div v-bind:class="{hide: hide, fadeout : fadeout}" class="product-wrapper @Columns @(!isSubstituteProduct ? "async-price " : "" ) js-favProduct" data-product-display="flex" data-product-key-clean='@(product.GetString("Ecom:Product.ID"))' data-product-key='@(product.GetJsonPriceKey((string)productListDefaultUnit.UnitId))' data-product-retail-price='@(product.GetJsonRetailPrice())' data-product-unit-information='@JsonConvert.SerializeObject(unitInformation)'>
<div itemscope itemtype="http://schema.org/Product" class="productlist-grid-product">
@{
var isNyhed = product.GetBoolean("Ecom:Product:Field.Nyhed.Value");
var isOutle = product.GetBoolean("Ecom:Product:Field.Outlet.Value");
}
@RenderProductLabels(tilbud, productGridIsVolumenDiscount, discountedCompletely, discountedTemporary, isNyhed, isOutle)
<a class="productlist-grid-image" href="@link" itemprop="url">
<img src="/Admin/Public/GetImage.ashx?Width=200&Height=200&Crop=5&Compression=80&Image=@Image"
class="img-responsive" alt="@System.Web.HttpUtility.HtmlEncode(product.GetString("Ecom:Product.Name"))" itemprop="image" />
</a>
<div class="productlist-grid-caption">
<a href="@link" class="productlist-grid-name" itemprop="name">
@System.Web.HttpUtility.HtmlEncode(product.GetString("Ecom:Product.Name"))
</a>
</div>
<div class="offer" itemprop="offers" itemscope="" itemtype="http://schema.org/Offer">
@if (!isSubstituteProduct)
{
<div class="productlist-grid-info">
<span class="productlist-grid-number">
@Translate("Product Number", "Product Number") <span itemprop="sku">@product.GetString("Ecom:Product.Number")</span>
</span>
<span class="productlist-grid-stock">
@if (Pageview.User.LoggedIn)
{
<span class="async-price-stock" itemprop="availability">
<span class="spinner-sm-default"></span>
</span>
}
else
{
@RenderStockInformations(product)
}
</span>
</div>
<div class="productlist-grid-footer">
<div class="productlist-grid-price-info">
<div class="productlist-grid-price js-price-container">
@if (Pageview.User.LoggedIn && !hidePrice)
{
<span class="async-price-unit"></span>
<span class="productlist-grid-price-price async-price-total" itemprop="price"></span>
}
</div>
</div>
@if (ObjectFactory.GetInstance<NORRIQ.Common8.Context.AreaItemSettings>().GetCurrentAreaValue<string>("ProductlistGridHideButton") == "False")
{
<div class="productlist-grid-buying">
@if (product.GetLoop("VariantGroups").Any())
{
<a href="@link" class="btn btn-buy">
<span class="product-added-text">@Translate("Buy", "Buy")</span>
</a>
}
else
{
<form class="form" id="[email protected]("Ecom:Product.ID")" name="[email protected]("Ecom:Product.ID")" method="post" action="/Default.aspx?ID=@GetGlobalValue("Global:Page.ID")">
@*
Because of DW and their use of Default units, we have to do this the manual way:
http://doc.dynamicweb.com/documentation-8/ecommerce/product-catalog/products#sideNavTitle1-2-5-4
The ones commented out has been deemed not necessary.
*@
@*@GetString("Ecom:Product.Form.Clean")*@
@*<input type="hidden" name="ProductURL" id="ProductURL" value="" />*@
<input type="hidden" name="CartCmd" value="add" />
<input type="hidden" name="ProductID" value="@(product.GetString("Ecom:Product.ID"))" />
<input type="hidden" name="VariantID" value="" />
@*<input type="hidden" name="UnitID" id="UnitID" value="STK" />*@
@*<input type="hidden" name="wishListID" id="wishListID" value="0" />*@
@{
}
<ordering-list-request-product-condition product-key='@product.GetString("Ecom:Product.ID")' inline-template>
<div class="">
<template v-if="loading">
<div class="loading">
<span class="spinner-sm-default"></span>
</div>
</template>
<div v-show="!loading" class="input-group popover-trigger">
<input name="quantity" value="1" min="1" max="99999" type="number" class="form-control text-center" autocomplete="off" data-trigger="focus" data-rule-number="true" data-rule-min="1" :disabled="isRestricted && !isAvailable" />
<span class="input-group-btn">
<select name="UnitId" class="form-control form-unit unit-input JS-ASYNC-UNITSELECTOR JS-ASYNC-INPUT-VALUE" @(productListUnits.Count() <= 1 ? "readonly" : "")>
@foreach (var unit in productListUnits)
{
<option value="@unit.UnitId" @(String.Equals(unit.UnitId, productListDefaultUnit.UnitId) ? "selected" : "")>@unit.UnitName</option>
}
</select>
</span>
</div>
<div class="hide my-popover-content">
@RazorProductSupplementalPopup(unitInformation)
</div>
</div>
</ordering-list-request-product-condition>
@if (Pageview.User.LoggedIn)
{
@RenderBuyButton(product, "grid")
}
</form>
}
</div>
}
</div>
}
else
{
//if the product is a substitution product render this section instead.
//This way to scope the feature is much easier to maintain changes in the future
<div class="productlist-grid-info">
<span class="productlist-grid-number">
@Translate("Product Number", "Product Number") <span itemprop="sku">@product.GetString("Ecom:Product.Number")</span>
</span>
<span class="productlist-grid-stock">
@RenderStockInformations(product, true)
</span>
</div>
<a class="btn btn-primary btn-block btn-air" href="@subStituteLink">@Translate("erstatningsvare")</a>
}
</div>
@if (isLoggedIn && !product.GetLoop("VariantGroups").Any())
{
<div class="productlist-grid-buttons">
@RenderFavoriteListIcon(product)
</div>
}
</div>
</div>
</template>
</product>
}
</template>
}
</slick>
</section>
}
else
{
<div class="productlist-grid-flex">
@foreach (var product in relatedProductList)
{
<template>
@using System.Globalization
@using System.Web.Mvc.Html
@using Dynamicweb.NewsLetterV3
@using NORRIQ.EcomMedia
@using StandardWebshop.CustomCode.Razor
@using NORRIQ.Common8.Razor;
@using NORRIQ.Common8.Factory
@using Newtonsoft.Json
@using Dynamicweb.eCommerce.Common;
@using Dynamicweb.eCommerce.Products
@using StandardWebshop.CustomCode.SupplementalUnit
@using StandardWebshop.CustomCode.ViewModels.Variants;
@using StandardWebshop.CustomCode.Volumenpriser
@using StandardWebshop.CustomCode.Units;
@using StandardWebshop.CustomCode.Units.Models
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@{
var currentUser = Dynamicweb.Modules.UserManagement.User.GetCurrentUser();
var hidePrice = false;
if (currentUser != null)
{
hidePrice = currentUser.CustomFieldValues.FirstOrDefault(cf => cf.CustomField.SystemName == "AccessUser_HidePrices").Value.ToString().ToLower() == "true" ? true : false;
}
//this is required do to lazy loading
//product.GetLoop("Units").Select(u => new
//{
// UnitId = u.GetString("Ecom:VariantOption.ID"),
// // Change the number format here:
// UnitPriceDouble = (u.GetDouble("Ecom:VariantOption.Price.PricePIP") / 100d),
// UnitName = u.GetString("Ecom:VariantOption.Name"),
// UnitObj = u
//}).OrderBy(x => x.UnitPriceDouble);
var link = product.GetString("NIQ:ProductUrl");
var tilbud = product.GetBoolean("Ecom:Product:Field.Tilbud.Value");
var buy = "/default.aspx?ID=" + Navigation.GetPageIdByNavigationTag("ecom") + "&productid=" + product.GetString("Ecom:Product.ID") + "&cartcmd=add";
var area = GetGlobalValue("Global:Area.Lang");
var media = NORRIQ.EcomMedia.Frontend.GetProductMedia(product);
var ProductSpecs = product.GetProductSpecifications();
var Image = ProductSpecs.GetAllByKey("Image").Any() ? "/Files/Images/XPI/" + ProductSpecs.GetByKey("Image").Value : media.GetFirstImage().Url;
var isLoggedIn = Pageview.User.LoggedIn;
var priceForGoogle = product.GetString("NIQ:PriceForGoogle");
var btn_addText = Translate("Add to cart", "Add to cart");
// Units
var unitInformation = product.GetUnitInformation() as UnitInformationViewModel;
var productListUnits = unitInformation.Units;
var productListDefaultUnit = unitInformation.ProductDefaultUnit;
//volumenPrices
var productgridVolumenpriser = product.GetVolumenpriser();
bool discountedCompletely = product.GetBoolean("NIQ:Product.DiscontunedCompletely");
bool discountedTemporary = product.GetBoolean("NIQ:Product.DiscontunedTemporary");
bool isSubstituteProduct = discountedTemporary || discountedCompletely;
string substituteProductID = product.GetString("NIQ:Product.SubstituteProductId");
string subStituteLink = string.Empty;
if (isSubstituteProduct && substituteProductID != null)
{
subStituteLink = string.Format("/Default.aspx?ID={0}&productID={1}", NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("ecom"), substituteProductID);
}
tilbud = tilbud || productListUnits.Any(x => x.IsInformativePrice);
var productGridIsVolumenDiscount = productgridVolumenpriser.HasPrices() && productgridVolumenpriser.IsValid();
}
@if (productListDefaultUnit != null)
{
<product product-key="@product.GetString("Ecom:Product.ID")" inline-template>
<template>
<div v-bind:class="{hide: hide, fadeout : fadeout}" class="product-wrapper @Columns @(!isSubstituteProduct ? "async-price " : "" ) js-favProduct" data-product-display="flex" data-product-key-clean='@(product.GetString("Ecom:Product.ID"))' data-product-key='@(product.GetJsonPriceKey((string)productListDefaultUnit.UnitId))' data-product-retail-price='@(product.GetJsonRetailPrice())' data-product-unit-information='@JsonConvert.SerializeObject(unitInformation)'>
<div itemscope itemtype="http://schema.org/Product" class="productlist-grid-product">
@{
var isNyhed = product.GetBoolean("Ecom:Product:Field.Nyhed.Value");
var isOutle = product.GetBoolean("Ecom:Product:Field.Outlet.Value");
}
@RenderProductLabels(tilbud, productGridIsVolumenDiscount, discountedCompletely, discountedTemporary, isNyhed, isOutle)
<a class="productlist-grid-image" href="@link" itemprop="url">
<img src="/Admin/Public/GetImage.ashx?Width=200&Height=200&Crop=5&Compression=80&Image=@Image"
class="img-responsive" alt="@System.Web.HttpUtility.HtmlEncode(product.GetString("Ecom:Product.Name"))" itemprop="image" />
</a>
<div class="productlist-grid-caption">
<a href="@link" class="productlist-grid-name" itemprop="name">
@System.Web.HttpUtility.HtmlEncode(product.GetString("Ecom:Product.Name"))
</a>
</div>
<div class="offer" itemprop="offers" itemscope="" itemtype="http://schema.org/Offer">
@if (!isSubstituteProduct)
{
<div class="productlist-grid-info">
<span class="productlist-grid-number">
@Translate("Product Number", "Product Number") <span itemprop="sku">@product.GetString("Ecom:Product.Number")</span>
</span>
<span class="productlist-grid-stock">
@if (Pageview.User.LoggedIn)
{
<span class="async-price-stock" itemprop="availability">
<span class="spinner-sm-default"></span>
</span>
}
else
{
@RenderStockInformations(product)
}
</span>
</div>
<div class="productlist-grid-footer">
<div class="productlist-grid-price-info">
<div class="productlist-grid-price js-price-container">
@if (Pageview.User.LoggedIn && !hidePrice)
{
<span class="async-price-unit"></span>
<span class="productlist-grid-price-price async-price-total" itemprop="price"></span>
}
</div>
</div>
@if (ObjectFactory.GetInstance<NORRIQ.Common8.Context.AreaItemSettings>().GetCurrentAreaValue<string>("ProductlistGridHideButton") == "False")
{
<div class="productlist-grid-buying">
@if (product.GetLoop("VariantGroups").Any())
{
<a href="@link" class="btn btn-buy">
<span class="product-added-text">@Translate("Buy", "Buy")</span>
</a>
}
else
{
<form class="form" id="[email protected]("Ecom:Product.ID")" name="[email protected]("Ecom:Product.ID")" method="post" action="/Default.aspx?ID=@GetGlobalValue("Global:Page.ID")">
@*
Because of DW and their use of Default units, we have to do this the manual way:
http://doc.dynamicweb.com/documentation-8/ecommerce/product-catalog/products#sideNavTitle1-2-5-4
The ones commented out has been deemed not necessary.
*@
@*@GetString("Ecom:Product.Form.Clean")*@
@*<input type="hidden" name="ProductURL" id="ProductURL" value="" />*@
<input type="hidden" name="CartCmd" value="add" />
<input type="hidden" name="ProductID" value="@(product.GetString("Ecom:Product.ID"))" />
<input type="hidden" name="VariantID" value="" />
@*<input type="hidden" name="UnitID" id="UnitID" value="STK" />*@
@*<input type="hidden" name="wishListID" id="wishListID" value="0" />*@
@{
}
<ordering-list-request-product-condition product-key='@product.GetString("Ecom:Product.ID")' inline-template>
<div class="">
<template v-if="loading">
<div class="loading">
<span class="spinner-sm-default"></span>
</div>
</template>
<div v-show="!loading" class="input-group popover-trigger">
<input name="quantity" value="1" min="1" max="99999" type="number" class="form-control text-center" autocomplete="off" data-trigger="focus" data-rule-number="true" data-rule-min="1" :disabled="isRestricted && !isAvailable" />
<span class="input-group-btn">
<select name="UnitId" class="form-control form-unit unit-input JS-ASYNC-UNITSELECTOR JS-ASYNC-INPUT-VALUE" @(productListUnits.Count() <= 1 ? "readonly" : "")>
@foreach (var unit in productListUnits)
{
<option value="@unit.UnitId" @(String.Equals(unit.UnitId, productListDefaultUnit.UnitId) ? "selected" : "")>@unit.UnitName</option>
}
</select>
</span>
</div>
<div class="hide my-popover-content">
@RazorProductSupplementalPopup(unitInformation)
</div>
</div>
</ordering-list-request-product-condition>
@if (Pageview.User.LoggedIn)
{
@RenderBuyButton(product, "grid")
}
</form>
}
</div>
}
</div>
}
else
{
//if the product is a substitution product render this section instead.
//This way to scope the feature is much easier to maintain changes in the future
<div class="productlist-grid-info">
<span class="productlist-grid-number">
@Translate("Product Number", "Product Number") <span itemprop="sku">@product.GetString("Ecom:Product.Number")</span>
</span>
<span class="productlist-grid-stock">
@RenderStockInformations(product, true)
</span>
</div>
<a class="btn btn-primary btn-block btn-air" href="@subStituteLink">@Translate("erstatningsvare")</a>
}
</div>
@if (isLoggedIn && !product.GetLoop("VariantGroups").Any())
{
<div class="productlist-grid-buttons">
@RenderFavoriteListIcon(product)
</div>
}
</div>
</div>
</template>
</product>
}
</template>
}
</div>
}
}
}
}
}
</template>
</div>
</div>
</div>
</div>
</div>
</template>
</product-page>
<script append="true">
var getPrices = @(Pageview.User.LoggedIn ? 1 : 0);
require(['jquery', 'lodash', 'standardwebshop/areas/ecom/product', 'jsrender'], function ($, _, product) {
var units = @JsonConvert.SerializeObject(units);
var productOptions = {
containerScope: '.js-product-scope .async-price',
getPrices: getPrices,
asyncTemplate: $('#async-price'),
unitCaptionMap: units, //get from template
baseUnit: "@volumenpriser.BaseUnit",
currencyCode: "@ProductCurrency",
currentCulture: "@System.Globalization.CultureInfo.CurrentCulture.Name"
};
product.init(productOptions);
});
require(['standardwebshop/areas/ecom/product-list'], function (productList) {
productList.init({
containerScope: '.product-related .async-price',
asyncTemplate: $('#async-price'),
productSort: $('#sortProducts'),
getPrices: getPrices,
unitContainerScope: '.product-related .JS-ASYNC-UNITSELECTOR',
//unit-selector options
baseUnit: "", // Get from data
currencyCode: "@ProductCurrency",
currentCulture: "@System.Globalization.CultureInfo.CurrentCulture.Name"
});
});
</script>