Error executing template "Designs/Bolind/eCom/ProductCatalog/basic_Pim.cshtml"
System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at CompiledRazorTemplates.Dynamic.RazorEngine_cf8ae037646c4e018853eec6b8df0114.Execute() in E:\Solutions\Bolind\Web\Live\Files\Templates\Designs\Bolind\eCom\ProductCatalog\basic_Pim.cshtml:line 58
at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.b__0(TextWriter writer)
at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @using System.Globalization
2 @using NLWI.Core.Factory
3 @using System.Linq;
4 @using Bolind.Web.CustomCode
5 @using Bolind.Web.CustomCode.CDN
6 @using Bolind.Web.CustomCode.Ecom.NonProducts.Fees
7 @using Bolind.Web.CustomCode.Ecom.NonProducts.Fittings
8 @using Bolind.Web.CustomCode.Ecom.NonProducts.Insurances
9 @using Bolind.Web.CustomCode.Ecom.ProductInformation
10 @using Bolind.Web.Files.Templates.Designs.Bolind.eCom.ProductCatalog.Model
11 @using Dynamicweb.Ecommerce
12 @using Dynamicweb.Ecommerce.Common
13 @using Dynamicweb.Ecommerce.Prices
14 @using Dynamicweb.Ecommerce.Products
15 @using Dynamicweb.Security.UserManagement.Synchronization
16 @using NORRIQ.Seo.Canonical
17 @using Newtonsoft.Json
18 @using NLWI.Platforms.Dynamicweb9.Specs.ViewModels
19 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Ecommerce.ProductCatalog.ProductViewModel>
20 @{
21 // Configuration
22 var basicPimPrefix = "PDP ";
23 var isReplacementSearch = System.Web.HttpContext.Current.Request.QueryString["isReplacementSearch"] != null;
24
25 // Specs
26 var specs = Model.GetSpecifications();
27 var specsToList = new HashSet<string>(specs.GetByKey("WebListFields").Value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries));
28 var minPurchase = Model.GetMinPurchase();
29 var stockFactor = Model.GetStockFactor();
30 var escapeMinPurch = Model.GetEscapeMinPurch();
31 var unit = Model.GetUnitId();
32 var fittings = Model.GetFittings();
33 var replacementProductsIds = Model.GetReplacementProducts();
34 var listPrice = Model.GetListPrice();
35 var ABC = Model.GetAbcCategory();
36 var extraWarranty = Model.IsExtraWarrantyMarked();
37 var betterchoise = Model.IsBolindBetterChoise();
38 var isCampaign = Model.IsCampaign();
39 var relatedProducts = Model.GetRelatedProducts();
40 var spareParts = Model.GetSpareParts();
41 var listedSpecs = specs.GetAvailableKeys().Where(a => specsToList.Contains(a) || specsToList.Count == 0).ToList();
42 var vatPercent = Model.Price.VATPercent;
43 var taxProducts = Model.GeTaxProducts();
44 var splashSpecs = specs.GetAllByKey("WebSplash").FirstOrDefault();
45 var splash = splashSpecs?.GetReferenceSpecification();
46 var showSplash = splash != null && Model.ShowSplash();
47 var isExtendedPdp = Model.IsExtendedPdp();
48 var quantityPrices = Model.GetQuantityPrices();
49 var hasLongDeliveryTime = Model.HasLongDeliveryTime();
50 var hasManyInStock = Model.HasManyInStock();
51 var isOperatingGoodsGroup = Model.IsOperatingGoodsGroup();
52 var isAppliances = Model.IsAppliances();
53 var stockAmount = Model.DFStockAmount();
54 var extendedFields = new HashSet<string>(specs.GetByKey("WebDetailFields").Value.Split(','));
55 var altText = Model.GetAltText();
56 var hasInsurance = Model.GetInsuranceField() != "";
57 var perfionId = Model.GetPerfionId();
58 var productId = Services.ProductGroups.GetProductGroupRelations(Model.Id).First()?.GroupId;
59 var productGroup = Services.ProductGroups.GetGroup(productId);
60 // For extendedPDP
61 var brandName = specs.GetByKey("Brandname").Value;
62 var energyLabel = specs.GetByKey("Energilabel").Value;
63 var energyClass = specs.GetByKey("Energiklasse").Value;
64 var energyColor = specs.GetByKey("EnergiFarve").Value;
65 var supplierProductNumber = specs.GetByKey("Leverandørensvarenummer").Value;
66 var producType = specs.GetByKey("Produkttype").Value;
67 var salesBullets = specs.GetByKey("Bullets").Value.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
68 var documentationSecurityPaper = specs.GetByKey("Sikkerhedsdatablad");
69 var documentationProductPaper = specs.GetByKey("Produktdatablad");
70 var documentationLink = specs.GetByKey("Link");
71 var productSheetPdf = specs.GetByKey(""); // TODO add key for Product Sheet Pdf-path
72 var brandLogoGuid = Model.ProductFields["BrandLogoGuid"]?.Value?.ToString();
73 var energyClassGuid = Model.ProductFields["EnergyClassGuid"]?.Value?.ToString();
74 var hasEnergyClass = !string.IsNullOrEmpty(energyClassGuid);
75 var sustainableLogoGuidsString = Model.ProductFields["SustainableLogos"]?.Value?.ToString();
76 var sustainableLogoGuids = new List<string>();
77 var mainIsCoolDown = Model.GetIsMainProductCoolDown();
78 if (!string.IsNullOrEmpty(sustainableLogoGuidsString))
79 {
80 sustainableLogoGuids = sustainableLogoGuidsString.Split(';').ToList();
81 }
82
83 var showRelatedFirst = productGroup.ProductGroupFieldValues.GetProductGroupFieldValue("ShowAlternativeFirst").Value;
84 while (!showRelatedFirst.Equals(true) && productGroup.ParentGroups.FirstOrDefault() != null)
85 {
86 productGroup = productGroup.ParentGroups.FirstOrDefault();
87 showRelatedFirst = productGroup.ProductGroupFieldValues.GetProductGroupFieldValue("ShowAlternativeFirst").Value;
88 }
89
90 var energyLabelNew = specs.GetByKey("EnergilabelNEW").Value;
91 var hasNewEnergyLabel = false;
92
93 if (!string.IsNullOrEmpty(energyLabelNew))
94 {
95 DateTime newEnergilabelActiveFromSpec;
96 DateTime oldEnergilabelActiveToSpec;
97
98 if (DateTime.TryParse(specs.GetByKey("EnergilabelActiveTo").Value, out oldEnergilabelActiveToSpec) && oldEnergilabelActiveToSpec.Date > DateTime.Now.Date)
99 {
100 energyLabel = string.Empty;
101 }
102
103 if (DateTime.TryParse(specs.GetByKey("EnergilabelActiveFrom").Value, out newEnergilabelActiveFromSpec) && newEnergilabelActiveFromSpec.Date <= DateTime.Now.Date)
104 {
105 energyLabel = energyLabelNew;
106 hasNewEnergyLabel = true;
107 }
108 }
109
110 var allowZeroPrice = Model.AllowZeroPrice();
111
112 // Services
113 var urlService = ObjectFactory.GetInstance<IProductUrlService>();
114
115 // Variables
116 var B2C = Pageview.IsB2C();
117 var images = new List<ProductSpecification>();
118
119 var variantCodes = Model.GetVariants();
120
121 var primaryPhoto = specs.GetByKey("Primærfoto");
122 if (primaryPhoto != null && !string.IsNullOrEmpty(primaryPhoto.Value))
123 {
124 images.Add(primaryPhoto);
125 }
126
127 foreach (var img in specs.GetAllByKey("AlternativeBilleder"))
128 {
129 if (!string.IsNullOrEmpty(img.Value) && !images.Any(i => string.Equals(i.Value, img.Value)))
130 {
131 images.Add(img);
132 }
133 }
134
135 var actionColor = B2C ? "btn-success" : "btn-danger";
136
137 var extended = isExtendedPdp ? "extended" : "simple";
138 var priceWithVat = Model.Price.PriceWithVat.ToString("#.00");
139
140 // Produktblade
141 var basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
142 var produktbladUrl = basePath + "Files\\Reports\\Produktblade\\Produktblade\\" + Model.Number + ".pdf";
143 bool showProduktblad = System.IO.File.Exists(produktbladUrl);
144
145 var produktbladsPdfUrl = "/files/reports/produktblade/produktblade/" + Model.Number + ".pdf";
146
147 }
148
149 @{
150 var variants = new List<CustomVariant>();
151 if (variantCodes.Any())
152 {
153 var productService = ObjectFactory.GetInstance<ProductService>();
154 foreach (var code in variantCodes)
155 {
156 var p = productService.GetProductById(Model.Id, code, true);
157 var autoId = productService.GetProductFieldValue(p, "NiqProductAutoId") as int? ?? 0;
158 var isCoolDownProduct = productService.GetProductFieldValue(p, "IsCoolDownProduct") as bool? ?? false;
159 var textOne = Model.GetSpecificationsForSpecificProduct(autoId).GetByKey("VariantTextOne")?.Value ?? "";
160 var textTwo = Model.GetSpecificationsForSpecificProduct(autoId).GetByKey("VariantTextTwo")?.Value ?? "";
161 variants.Add(new CustomVariant(code, textOne, textTwo, isCoolDownProduct));
162 }
163 }
164
165 }
166 @if (Pageview.User != null)
167 {
168 <favorite-list ref="favoriteList"></favorite-list>
169 }
170 <product-details-simple-pim default-variant="@Model.VariantId"
171 :main-is-cool-down="@mainIsCoolDown.ToString().ToLower()"
172 item-number="@Model.Id"
173 :variants='@(variantCodes != null && variantCodes.Any() ? JsonConvert.SerializeObject(variants) : "[]")'
174 :images='@JsonConvert.SerializeObject(images.Select(a => a.Value).ToArray())'
175 :fullimages='@JsonConvert.SerializeObject(images.Select(a => Pageview.CdnWrap($"/Admin/Public/GetImage.ashx?Width=2000&Height=1600&Crop=5&Compression=90&Image={a.Value}")).ToArray())'
176 inline-template>
177
178 <div class="extended basic_pim" v-bind:class="{'initialized': initialized }" itemscope="" itemtype="https://schema.org/Product">
179 <section class="basic_pim-head">
180 @if (isExtendedPdp)
181 {
182 <h1 itemprop="name">
183 <span class="brand">@brandName</span>
184 <small>@producType, @supplierProductNumber</small>
185 </h1>
186
187 }
188 else
189 {
190 <h1 itemprop="name">
191 @Model.Name
192 @if (Model.ProductFields.Where(a => a.Key.Contains("Desc")).Any())
193 {
194 <small>
195 @foreach (var i in Model.ProductFields.Where(a => a.Key.Contains("Desc")))
196 {
197 <text>@i.Value.Value </text>
198 }
199 </small>
200 }
201 </h1>
202 }
203 @if (brandLogoGuid != null)
204 {
205 <img src="@Pageview.CdnWrap($"/Files/Images/Ecom/Brands/{brandLogoGuid}.png")" alt="@brandName" class="img-fluid" />
206 }
207 </section>
208 <section class="basic_pim-pdp">
209 <div class="basic_pim-media">
210 @if (showSplash)
211 {
212 var splashShape = splash.GetByKey("WebSplashShape").Value.ToLower();
213 var splashColor = splash.GetByKey("WebSplashColor").Value.ToLower();
214 var splashText = splash.GetByKey("WebSplashText").Value;
215 <span class="label-top @splashShape-@splashColor-lg">
216 <span class="splash-title">@splashText</span>
217 </span>
218 }
219 @if (betterchoise)
220 {
221 <div style="position: absolute; z-index: 5; display: flex; bottom: 130px; left: 50px">
222 <span class="label-bolig">
223 <img src="@Pageview.CdnWrap("/Files/Images/Graphics/betterchoise.png")"
224 class="img-fluid"
225 alt="@Translate(basicPimPrefix + "betterchoise", "betterchoise")"/>
226 </span>
227 </div>
228 }
229 <div class="label-wrap">
230
231
232 @if (extraWarranty)
233 {
234 <span class="label-ExtraWarranty">
235 <img src="@Pageview.CdnWrap("/Files/Images/Graphics/reklamationsret.png")"
236 class="img-fluid"
237 title="@Translate(basicPimPrefix + "UdvidetGarantiText", "Udvidet Garanti")"
238 alt="@Translate(basicPimPrefix + "Reklamationsret", "Reklamationsret")" style="height: 150px"/>
239 </span>
240 }
241 </div>
242 <gallery :items="$attrs.fullimages" :index="index" @@close="index = null">
243 </gallery>
244 <template v-if="$attrs.images.length > 1">
245 <slick ref="slick"
246 class="basic_pim-images basic_pim-slick-images"
247 id="pdp-images" title="@Translate(basicPimPrefix + "Zoom In", "Se billede")"
248 :options="slickPimOptionsImages">
249 <picture class="basic_pim-image" v-for="(image, imageIndex) in $attrs.images" :key="imageIndex" @@click="setIndex(imageIndex)">
250 <source media="(max-width:767.98px)" :srcset="'@Pageview.CdnWrap("/Admin/Public/GetImage.ashx?Width=300&Height=250&Compression=85&Crop=5&Image=")' + image">
251 <source media="(max-width:991.98px)" :srcset="'@Pageview.CdnWrap("/Admin/Public/GetImage.ashx?Width=400&Height=350&Compression=85&Crop=5&Image=")' + image">
252 <img :src="'@Pageview.CdnWrap("/Admin/Public/GetImage.ashx?Width=538&Height=508&Compression=85&Crop=5&Image=")' + image" alt="@altText" class="img-fluid" itemprop="image"/>
253 </picture>
254 </slick>
255 <slick ref="slick" class="basic_pim-thumbs" id="pdp-thumbs" :options="slickPimOptionsThumbs">
256 <figure v-for="thumb in $attrs.images" class="basic_pim-thumb">
257 <img :src="'@Pageview.CdnWrap("/Admin/Public/GetImage.ashx?Width=50&Height=50&Compression=85&Crop=5&Image=")' + thumb" alt="@altText" class="img-fluid"/>
258 </figure>
259 </slick>
260 </template>
261 <template v-if="$attrs.images.length == 1">
262 <div class="basic_view-images">
263 <picture class="basic_pim-image" title="@Translate(basicPimPrefix + "Zoom In", "Se billede")" v-for="(image, imageIndex) in $attrs.images" :key="imageIndex" @@click="setIndex(imageIndex)">
264 <source media="(max-width:767.98px)" :srcset="'@Pageview.CdnWrap("/Admin/Public/GetImage.ashx?Width=300&Height=250&Compression=85&Crop=5&Image=")' + image">
265 <source media="(max-width:991.98px)" :srcset="'@Pageview.CdnWrap("/Admin/Public/GetImage.ashx?Width=400&Height=350&Compression=85&Crop=5&Image=")' + image">
266 <img :src="'@Pageview.CdnWrap("/Admin/Public/GetImage.ashx?Width=538&Height=508&Compression=85&Crop=5&Image=")' + image" alt="@altText" class="img-fluid" itemprop="image">
267 </picture>
268 </div>
269 </template>
270 <template v-if="$attrs.images.length == 0">
271 @{
272 var pdpImage = "/Files/Images/Default.png";
273 }
274 <div class="basic_pim-image image-default">
275 <picture class="basic_view-images">
276 <source media="(max-width:48rem)" srcset="@Pageview.CdnWrap($"/Admin/Public/GetImage.ashx?Width=300&Height=250&Compression=85&Crop=5&Image={pdpImage}")">
277 <source media="(max-width:80rem)" srcset="@Pageview.CdnWrap($"/Admin/Public/GetImage.ashx?Width=400&Height=350&Compression=85&Crop=5&Image={pdpImage}")">
278 <img src="@Pageview.CdnWrap($"/Admin/Public/GetImage.ashx?Width=538&Height=508&Compression=85&Crop=5&Image={pdpImage}")" alt="@Translate(basicPimPrefix + "No product picture", "No product picture")" class="img-fluid" itemprop="image">
279 </picture>
280 </div>
281 </template>
282 </div>
283 <div class="basic_pim-content @extended">
284
285 @if (isExtendedPdp)
286 {
287 <section class="salespoints">
288 <div>
289 @if (Model.ProductFields.Where(a => a.Key.Contains("Desc")).Any())
290 {
291 <header>
292 <h2>
293 @foreach (var i in Model.ProductFields.Where(a => a.Key.Contains("Desc")))
294 {
295 <text>@i.Value.Value </text>
296 }
297 </h2>
298 </header>
299 }
300 @if (salesBullets.Any())
301 {
302 <main>
303 <ul class="list-unstyled listed">
304 @foreach (var bullet in salesBullets)
305 {
306 <li>@bullet</li>
307 }
308 </ul>
309 </main>
310 }
311 </div>
312
313 <div>
314 @if (hasEnergyClass)
315 {
316 <div class="energy energy-align">
317 <div class="energy-label energy-label-align">
318 <div class="energy-in">
319 <img src="@Pageview.CdnWrap("/Files/Images/Ecom/EnergyClass/" + energyClassGuid + ".png")"
320 class="img-fluid"
321 style="height: 40px;"/>
322 </div>
323 </div>
324 </div>
325 if (!string.IsNullOrEmpty(energyLabel))
326 {
327 <div class="energybookmark">
328 <a href="@Pageview.SearchFriendlyUrl#energylabel">@Translate("EU-Datablad", "EU-Datablad")</a>
329 </div>
330 }
331 }
332
333 @{
334 if (showProduktblad)
335 {
336 <div class="energybookmark">
337 <a href="@produktbladsPdfUrl" target="_blank"><img class="pdf-icon" src="/src/bolind/icons/pdf.svg" alt="PDF icon"/><br/>@Translate("Product-sheet", "Produktark")</a>
338 </div>
339 }
340 }
341
342 </div>
343 </section>
344 <ul class="list-unstyled stroked list-nav">
345 <li>
346 <a href="@Pageview.SearchFriendlyUrl#spec">@Translate(basicPimPrefix + "Se specs", "Se alle specifikationer")</a>
347 </li>
348 <li>
349 <a href="@Pageview.SearchFriendlyUrl#desc">@Translate(basicPimPrefix + "Se beskrivelse", "Se produktbeskrivelse")</a>
350 </li>
351 </ul>
352 }
353 @if (isReplacementSearch)
354 {
355 string originalSearchQuery = System.Web.HttpContext.Current.Request["originalSearchQuery"];
356
357 <p class="alert alert-warning alert-icon">
358 <svg class="larger">
359 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#info-circle"></use>
360 </svg>
361 <span class="wrap">
362 <span class="strong">
363 @Translate(basicPimPrefix + "Erstatningsvare-title", "Erstatningsvare")
364 </span><br/>
365
366 <span>
367 @Translate(basicPimPrefix + "Du har søgt på dette varenummer", "Du har søgt på dette varenummer") @originalSearchQuery, @Translate(basicPimPrefix + "som er udgået.", "som er udgået.")
368 <br/>
369 @Translate(basicPimPrefix + "Varen er erstattet af den viste vare") @Model.Number, @Translate(basicPimPrefix + "som svarer til den udgåede.")
370 </span>
371 </span>
372 </p>
373 }
374 @if (hasEnergyClass && !isExtendedPdp)
375 {
376 <section class="salespoints">
377 <div></div>
378 <div>
379 <div class="energy">
380 <div class="energy-label">
381 <div class="energy-in">
382 <img src="@Pageview.CdnWrap("/Files/Images/Ecom/EnergyClass/" + energyClassGuid + ".png")"
383 class="img-fluid"
384 style="height: 40px;"/>
385 </div>
386 </div>
387 </div>
388 @if (!string.IsNullOrEmpty(energyLabel))
389 {
390 <div class="energybookmark">
391 <a href="@Pageview.SearchFriendlyUrl#energylabel">@Translate("EU-Datablad", "EU-Datablad")</a>
392 </div>
393 }
394 </div>
395 </section>
396 }
397 @if (B2C || Pageview.User != null)
398 {
399 <div class="pricing" itemprop="offers" itemscope itemtype="https://schema.org/Offer">
400 <div class="priceinfo">
401 <p>
402 @{
403 foreach (var logoGuid in sustainableLogoGuids)
404 {
405 if (!string.IsNullOrEmpty(logoGuid))
406 {
407 <img src="@Pageview.CdnWrap("/Files/Images/Graphics/" + logoGuid + ".png")"
408 class="img-fluid"
409 style="max-height: 75px; margin-right: 8px" />
410 }
411 }
412 }
413 </p>
414 <p class="basic_pim-sku iconed" itemprop="sku">
415 <svg>
416 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#barcode"></use>
417 </svg>
418 @Translate(basicPimPrefix + "Product number", "Product number"): @Model.Number
419 </p>
420
421 @if (!mainIsCoolDown)
422 {
423 if (isOperatingGoodsGroup)
424 {
425 <p class="stockstatus" alt="Red" v-if="notInStock()">
426 <svg>
427 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
428 </svg>
429 <span>
430 @if (ABC == "A")
431 {
432 @Translate(basicPimPrefix + "Ikke på lager A", "Ikke på lager")
433 }
434 else if (ABC == "B")
435 {
436 @Translate(basicPimPrefix + "Ikke på lager B", "Ikke på lager")
437 }
438 else if (ABC == "C")
439 {
440 @Translate(basicPimPrefix + "Ikke på lager C", "Ikke på lager")
441 }
442 </span>
443 </p>
444
445 <p class="stockstatus" alt="A" v-if="manyInStock(@minPurchase, @stockFactor)">
446 <svg>
447 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
448 </svg>
449 <span>{{stock}} @Translate(basicPimPrefix + " DF på lager", "på lager")</span>
450 </p>
451
452 <p class="stockstatus" alt="B" v-if="!manyInStock(@minPurchase, @stockFactor) && !notInStock()">
453 <svg>
454 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
455 </svg>
456 <span>@Translate(basicPimPrefix + "Få på lager", "Få på lager")</span>
457 </p>
458
459 }
460 else if (isAppliances)
461 {
462 <p class="stockstatus" alt="Red" v-if="notInStock()">
463 <svg>
464 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
465 </svg>
466 <span>
467 @if (ABC == "A")
468 {
469 @Translate(basicPimPrefix + "Ikke på lager A", "Ikke på lager")
470 }
471 else if (ABC == "B")
472 {
473 @Translate(basicPimPrefix + "Ikke på lager B", "Ikke på lager")
474 }
475 else if (ABC == "C")
476 {
477 @Translate(basicPimPrefix + "Ikke på lager C", "Ikke på lager")
478 }
479 </span>
480 </p>
481
482 <p class="stockstatus" alt="A" v-if="manyInStock(1, 3)">
483 <svg>
484 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
485 </svg>
486 <span>{{stock}} @Translate(basicPimPrefix + " DF på lager", "på lager")</span>
487 </p>
488
489 <p class="stockstatus" alt="B" v-if="!manyInStock(1, 3) && !notInStock()">
490 <svg>
491 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
492 </svg>
493 <span>@Translate(basicPimPrefix + "Få på lager", "Få på lager")</span>
494 </p>
495 <div v-if="wagStock>0" class="stockstatus">
496 <svg style="fill: #004c6a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512">
497 <path d="M0 488V171.3c0-26.2 15.9-49.7 40.2-59.4L308.1 4.8c7.6-3.1 16.1-3.1 23.8 0L599.8 111.9c24.3 9.7 40.2 33.3 40.2 59.4V488c0 13.3-10.7 24-24 24H568c-13.3 0-24-10.7-24-24V224c0-17.7-14.3-32-32-32H128c-17.7 0-32 14.3-32 32V488c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24zm488 24l-336 0c-13.3 0-24-10.7-24-24V432H512l0 56c0 13.3-10.7 24-24 24zM128 400V336H512v64H128zm0-96V224H512l0 80H128z"/>
498 </svg>
499 <span>{{ wagStock }} @Translate(basicPimPrefix + " wag på lager", "på fjernlager")</span>
500 </div>
501 }
502 else
503 {
504 if (!string.IsNullOrEmpty(ABC) && !B2C)
505 {
506 <p class="stockstatus" alt="@ABC">
507 @if (ABC == "A")
508 {
509 <svg>
510 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
511 </svg>
512 <span>@Translate("ABC A Text", "Kort leveringstid")</span>
513 }
514 @if (ABC == "B")
515 {
516 <svg>
517 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
518 </svg>
519 <span>@Translate("ABC B Text", "Forvent leveringstid")</span>
520 }
521 </p>
522 }
523 }
524
525 if (isOperatingGoodsGroup && hasLongDeliveryTime)
526 {
527 <div>
528 <p>
529 <a href="#related-products" class="long-delivery-time">
530 @Translate(basicPimPrefix + "Lang leveringstid", "Denne vare har lang leveringstid. Se alternative her")
531 </a>
532 </p>
533 </div>
534 }
535 }
536 </div>
537 <div class="prices">
538 @if (Pageview.User != null)
539 {
540 <async-price class-type="asyncprice-pdp"
541 default-price-without-vat="@Model.Price.PriceWithoutVat"
542 product-id="@Model.Id"
543 :variant-id="variantId"
544 unit-of-measure="@unit"
545 :list-price="@JsonConvert.SerializeObject(listPrice)"
546 price-group=""
547 is-campaign="@isCampaign"
548 @@update-stock="setLiveStock"
549 :is-cool-down-product="isCoolDown"
550 :allow-zero-price="@allowZeroPrice.ToString().ToLower()">
551 </async-price>
552 }
553 else if (B2C)
554 {
555 <p class="listprice" v-if="showListPrice(@listPrice, @Model.Price.PriceWithVat)">
556 @Translate("product_listPrice", "Vejledende pris:") <span>@listPrice.ToString("#.00")</span>
557 </p>
558 <p class="price">
559 <template v-if="'@isCampaign' == 'True'">
560 <span class="price-campaigntext">@Translate(basicPimPrefix + "Campaign_price", "Kampagnepris")</span>
561 </template>
562 <span itemprop="price" class="price-actual" content="@priceWithVat">
563 @priceWithVat
564 </span><span itemprop="priceCurrency" content="@Context.Currency.Code" class="hide"></span>
565 </p>
566 <p class="priceper">
567 @Translate("product_pricePer", "Pris pr.") @unit.ToLower() @Translate("product_inclVat", "inkl. moms")
568 </p>
569
570 if (quantityPrices.Any())
571 {
572 <ul class="list-inline qtyPrices">
573 <li>
574 @Translate(basicPimPrefix + "quantity_prices_ex_moms", "Flerstk priser vises ekskl. moms")
575 </li>
576 @foreach (var quantityPrice in quantityPrices)
577 {
578 if (Model.Price.PriceWithVat > quantityPrice.Price)
579 {
580 <li>
581 <span>@Translate(basicPimPrefix + "Price pr. unit", "Fra") @quantityPrice.Quantity @unit.ToLower() </span>
582 <span class="qtyprice">{{@quantityPrice.Price | currency(true)}}</span>
583 </li>
584 }
585 }
586 </ul>
587 }
588 }
589 </div>
590 </div>
591 if (Model.GetProduct().IsActive)
592 {
593 <div class="basic_pim-action">
594 <div class="basic_pim-buying">
595 @if (mainIsCoolDown)
596 {
597 <substitute-products inline-template :item-number="'@Model.Number'">
598 <div class="alert-wrapper" v-if="productList.length>0">
599 <p class="alert alert-success">
600 <b>@Translate("Substitutes", "Erstatningsvarer")</b>
601 <template v-for="(p,i) in productList">
602 <div style="display: flex; cursor: pointer; margin-top: 8px;" @@click="clickSubProduct(p.Url)">
603 <img src="/files/images/ecom/icons/product.png" width="20" height="20"/>
604 <div style="margin-left: 12px">
605 <div style="font-size: 16px; font-weight: 500">
606 {{p.Name}}
607 </div>
608 <div style="font-size: 12px; font-weight: 500">
609 Varenr. {{p.Number}}
610 </div>
611 </div>
612 </div>
613 </template>
614 </p>
615 </div>
616 </substitute-products>
617 }
618 @{
619 if (hasInsurance)
620 {
621 <div class="alert-wrapper">
622 <p class="alert alert-success">
623 <svg class="icon">
624 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#file-contract"></use>
625 </svg>
626 <strong>@Translate("Insurance news tag", "NYHED")</strong> @Translate("Insurance can be choosed", "På denne vare kan der tilkøbes forsikring")
627 </p>
628 </div>
629 }
630 }
631 @foreach (var i in Model.GeTaxProducts())
632 {
633 <p class="charge">
634 <span class="charge-name">
635 @i.Name:
636 </span>
637 <span class="charge-price">
638 @if (B2C)
639 {
640 @((i.Price + (vatPercent / 100 * i.Price)).ToString("#.00"))
641 }
642 else
643 {
644 @(i.Price.ToString("#.00"))
645 }
646 </span>
647 </p>
648 }
649 @if (minPurchase > 1)
650 {
651 <p class="minQty">
652 <svg>
653 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#info-circle"></use>
654 </svg>
655 <span>
656 @Translate("product_minPurchase", "Sælges kun i hele kolli á:") @minPurchase @unit.ToLower()
657 </span>
658 </p>
659
660 }
661 @if (Model.Variants != null && Model.Variants.Any())
662 {
663 <div class="basic_pim-variants">
664 <div class="basic_pim-variant">
665 <div class="form-group">
666 <label for="@Model.Id">
667 @Translate(basicPimPrefix + "Variants", "Variants")
668 </label>
669 <select autocomplete="off" v-model="variant1" class="form-control" id="variantdropdown">
670 <option selected value="">@Translate(basicPimPrefix + "PickVariant select", "- Vælg -")</option>
671 <option v-for="(variant,index) in variant1Options" :key="index">{{variant.variant1}}</option>
672 </select>
673 </div>
674 <div v-if="variant2Options.length > 0" class="form-group">
675 <select v-model="variant2" class="form-control">
676 <option value="">@Translate(basicPimPrefix + "PickVariant select", "- Vælg -")</option>
677 <option v-for="variant in variant2Options">{{variant.variant2}}</option>
678 </select>
679 </div>
680 </div>
681 </div>
682 }
683 <div class="basic_pim-buttons">
684 <template>
685 @if (Pageview.User != null)
686 {
687 <favorite-item product-id="@Model.Id"
688 language-id="@Model.LanguageId"
689 :variant-id="variantId"
690 ref="favoriteItem">
691 </favorite-item>
692 }
693 </template>
694 <template v-if="!noVariantPicked">
695 <add-to-basket-rounding class="addtobasketrounding-pdp"
696 ref="basket"
697 :is-cool-down-product="isCoolDown"
698 button-class="btn @actionColor btn-icon"
699 product-id="@Model.Id"
700 :variant-id="variantId"
701 language-id="@Model.LanguageId"
702 min-purchase="@minPurchase"
703 escape-min-purch="@escapeMinPurch"
704 :has-montage="hasMontage"
705 :missing-variant="missingVariant"
706 unit-of-measure="@unit"
707 :is-b2c="@B2C.ToString().ToLower()">
708 </add-to-basket-rounding>
709 </template>
710 </div>
711 </div>
712 </div>
713 }
714 else
715 {
716 <div class="alert-wrapper">
717 <p class="alert alert-info">
718 <svg>
719 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/files/dist/icons/icons.svg#tools">
720 </use>
721 </svg>
722 @Translate("product-inactive", "Produktet er inaktivt og kan derfor ikke lægges i indkøbskurven.")
723 </p>
724 </div>
725 }
726 }
727 else
728 {
729 <div class="pricing">
730 <div class="priceinfo">
731 <p>
732 @{
733 foreach (var logoGuid in sustainableLogoGuids)
734 {
735 if (!string.IsNullOrEmpty(logoGuid))
736 {
737 <img src="@Pageview.CdnWrap("/Files/Images/Graphics/" + logoGuid + ".png")"
738 class="img-fluid"
739 style="max-height: 75px; margin-right: 8px"/>
740 }
741 }
742 }
743 </p>
744 <p class="basic_pim-sku iconed">
745 <svg>
746 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#barcode"></use>
747 </svg>
748 @Translate(basicPimPrefix + "Product number", "Product number"): <span itemprop="sku">@Model.Number</span>
749 </p>
750 </div>
751 </div>
752 <div class="basic_pim-action">
753 <div class="basic_pim-buying">
754 <div class="basic_pim-unauthed">
755
756 <label class="btn btn-danger btn-lg btn-icon" for="login-toggle">
757 <svg>
758 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#user"></use>
759 </svg>
760 @Translate(basicPimPrefix + "Log in to see prices", "Log ind for at se priser og handle")
761 </label>
762 </div>
763 </div>
764 </div>
765 }
766 </div>
767 </section>
768
769 @if (showRelatedFirst.Equals(true))
770 {
771 <section class="basic_view-related-wrap">
772 @if (spareParts != null && spareParts.Any())
773 {
774 <section class="basic_listview basic_view-related">
775 <template>
776 <header>
777 <h2>
778 @Translate(basicPimPrefix + "Spare parts", "Spare parts")
779 </h2>
780 </header>
781 <div class="basic_listview-grid related">
782 @foreach (var sparePartRelation in spareParts)
783 {
784 var sparePart = sparePartRelation.Product;
785 var url = urlService.GetProductUri(sparePart.Id, sparePart.VariantId);
786 var sparePartUnitId = sparePart.GetUnitId();
787 var sparePartProductImage = sparePart.GetPrimaryImage();
788
789 if (string.IsNullOrEmpty(sparePartProductImage))
790 {
791 sparePartProductImage = "/Files/Images/Default.png";
792 }
793 var sparePartListPrice = sparePart.GetListPrice();
794 var sparePartMinPurchase = sparePart.GetMinPurchase();
795 var sparePartEscapeMinPurch = sparePart.GetEscapeMinPurch();
796 var sparePartABC = sparePart.GetAbcCategory();
797 var sparePartIsCoolDown = sparePart.GetIsMainProductCoolDown();
798 var sparePartDescriptions = sparePart.ProductFieldValues.Where(a => a.GetFieldName().Contains("Desc")).ToList();
799 var sparePartIsCampaign = sparePart.IsCampaign();
800 var sparePartPriceWithVat = sparePart.Price.PriceWithVAT.ToString("#.00");
801 var sparePartAltText = sparePart.GetAltText();
802
803 <article class="basic_view-related--product" ppp="@sparePart.Id">
804 <div class="innerwrap">
805 <a href="@url.PathAndQuery">
806 <figure>
807 <img src="@Pageview.CdnWrap($"/Admin/Public/GetImage.ashx?Width=250&Height=130&Compression=85&Crop=5&Image={sparePartProductImage}")"
808 alt="@sparePartAltText"
809 itemprop="image"
810 class="img-fluid"/>
811 </figure>
812 </a>
813 <header>
814 <div>
815 <a href="@url.PathAndQuery" itemprop="url">
816 <h1 itemprop="name">@sparePart.Name</h1>
817 <p itemprop="description">
818 @if (sparePartDescriptions.Any())
819 {
820 <span>
821 @foreach (var i in sparePartDescriptions)
822 {
823 @i.Value
824 }
825 </span>
826 }
827 </p>
828 </a>
829 <p class="sku"><span itemprop="sku">@Translate(basicPimPrefix + "Product Number", "Product Number") @sparePart.Number</span></p>
830 </div>
831 </header>
832 </div>
833 <footer>
834 <div class="basic_listview-pricing">
835 @if (Pageview.User != null)
836 {
837 <async-price class-type="asyncprice-plp"
838 default-price-without-vat="@sparePart.Price.PriceWithoutVAT"
839 :is-cool-down-product="@sparePartIsCoolDown.ToString().ToLower()"
840 product-id="@sparePart.Id"
841 :variant-id="variantId"
842 unit-of-measure="@sparePartUnitId"
843 :list-price="@JsonConvert.SerializeObject(sparePartListPrice)"
844 is-campaign="@sparePartIsCampaign"
845 @@update-stock="setLiveStock">
846 </async-price>
847 }
848 else if (B2C)
849 {
850 <p class="listprice" v-if="showListPrice(@sparePartListPrice, @sparePart.Price.PriceWithVAT)">
851 @Translate("product_listPrice", "Vejledende pris:") <span>@sparePartListPrice.ToString("#.00")</span>
852 </p>
853 <p class="price">
854 <template v-if="'@sparePartIsCampaign' == 'True'">
855 <span class="price-campaigntext">@Translate(basicPimPrefix + "Campaign_price", "Kampagnepris")</span>
856 </template>
857 <span itemprop="price" class="price-actual" content="@sparePartPriceWithVat">
858 @sparePartPriceWithVat
859 </span><span itemprop="priceCurrency" content="@Context.Currency.Code" class="hide"></span>
860 </p>
861 <p class="priceper">
862 @Translate("product_pricePer", "Pris pr.") @unit.ToLower() @Translate("product_inclVat", "inkl. moms")
863 </p>
864 }
865 <div class="basic_listview-delivery only-grid">
866 @if (!string.IsNullOrEmpty(sparePartABC))
867 {
868 if (Pageview.User != null)
869 {
870 <p class="stockstatus" alt="@sparePartABC">
871 @if (sparePartABC == "A")
872 {
873 <svg>
874 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
875 </svg>
876 <span>@Translate("ABC A Text", "Kort leveringstid")</span>
877 }
878 @if (sparePartABC == "B")
879 {
880 <svg>
881 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
882 </svg>
883 <span>@Translate("ABC B Text", "Forvent leveringstid")</span>
884 }
885 </p>
886 }
887 }
888 @if (sparePartMinPurchase > 1)
889 {
890 <p class="minQty">
891 <svg>
892 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#info-circle"></use>
893 </svg>
894 <span>
895 @Translate("product_minPurchase", "Sælges kun i hele kolli á:") @sparePartMinPurchase @sparePartUnitId.ToLower()
896 </span>
897 </p>
898
899 }
900 </div>
901 <div class="basic_listview-buttons">
902 <div class="@(B2C ? "b2c" : "b2b")">
903 @if ((B2C || Pageview.User != null) && sparePart.VariantCount == 0)
904 {
905 <add-to-basket-rounding class="addtobasketrounding-plp"
906 button-class="btn @actionColor btn-icon icon-only"
907 product-id="@sparePart.Id"
908 variant-id="@sparePart.VariantId"
909 language-id="@sparePart.LanguageId"
910 min-purchase="@sparePartMinPurchase"
911 :is-cool-down-product="@sparePartIsCoolDown.ToString().ToLower()"
912 escape-min-purch="@sparePartEscapeMinPurch"
913 :has-montage="false"
914 :missing-variant="false"
915 unit-of-measure="@sparePartUnitId"
916 :is-b2c="@B2C.ToString().ToLower()">
917 </add-to-basket-rounding>
918 }
919 else
920 {
921 <a class="btn @actionColor" href="@url.PathAndQuery">
922 @Translate("Show product", "Vis vare")
923 </a>
924 }
925 </div>
926 </div>
927 </div>
928 </footer>
929 </article>
930 }
931 </div>
932 </template>
933 </section>
934 }
935
936 @if (relatedProducts != null && relatedProducts.Any())
937 {
938 <section class="basic_listview basic_view-related" id="related-products">
939 <template>
940 <header>
941 <h2>
942 @Translate(basicPimPrefix + "Related Products", "Related Products")
943 </h2>
944 </header>
945 <div class="basic_listview-grid related">
946 @foreach (var related in relatedProducts)
947 {
948 var relatedProduct = related.Product;
949 var url = urlService.GetProductUri(relatedProduct.Id, relatedProduct.VariantId);
950 var relatedUnitId = relatedProduct.GetUnitId();
951 var relatedProductImage = relatedProduct.GetPrimaryImage();
952
953 if (string.IsNullOrEmpty(relatedProductImage))
954 {
955 relatedProductImage = "/Files/Images/Default.png";
956 }
957 var relatedListPrice = relatedProduct.GetListPrice();
958 var relatedMinPurchase = relatedProduct.GetMinPurchase();
959 var relatedEscapeMinPurch = relatedProduct.GetEscapeMinPurch();
960 var relatedIsCoolDown = relatedProduct.GetIsMainProductCoolDown();
961 var relatedABC = relatedProduct.GetAbcCategory();
962 var relatedProductDescriptions = relatedProduct.ProductFieldValues.Where(a => a.GetFieldName().Contains("Desc")).ToList();
963 var relatedIsCampaign = relatedProduct.IsCampaign();
964 var relatedPriceWithVat = relatedProduct.Price.PriceWithVAT.ToString("#.00");
965 var relatedAltText = relatedProduct.GetAltText();
966
967 <article class="basic_view-related--product" ppp="@relatedProduct.Id">
968 <div class="innerwrap">
969 <a href="@url.PathAndQuery">
970 <figure>
971 <img src="@Pageview.CdnWrap($"/Admin/Public/GetImage.ashx?Width=250&Height=130&Compression=85&Crop=5&Image={relatedProductImage}")"
972 alt="@relatedAltText"
973 itemprop="image"
974 class="img-fluid"/>
975 </figure>
976 </a>
977 <header>
978 <div>
979 <a href="@url.PathAndQuery" itemprop="url">
980 <h1 itemprop="name">@relatedProduct.Name</h1>
981 <p itemprop="description">
982 @if (relatedProductDescriptions.Any())
983 {
984 <span>
985 @foreach (var i in relatedProductDescriptions)
986 {
987 @i.Value
988 }
989 </span>
990 }
991 </p>
992 </a>
993 <p class="sku"><span itemprop="sku">@Translate(basicPimPrefix + "Product Number", "Product Number") @relatedProduct.Number</span></p>
994 </div>
995 </header>
996 </div>
997 <footer>
998 <div class="basic_listview-pricing">
999 @if (Pageview.User != null)
1000 {
1001 <async-price class-type="asyncprice-plp"
1002 default-price-without-vat="@relatedProduct.Price.PriceWithoutVAT"
1003 product-id="@relatedProduct.Id"
1004 :variant-id="variantId"
1005 :is-cool-down-product="@relatedIsCoolDown.ToString().ToLower()"
1006 unit-of-measure="@relatedUnitId"
1007 :list-price="@JsonConvert.SerializeObject(relatedListPrice)"
1008 is-campaign="@relatedIsCampaign"
1009 @@update-stock="setLiveStock">
1010 </async-price>
1011 }
1012 else if (B2C)
1013 {
1014 <p class="listprice" v-if="showListPrice(@relatedListPrice, @relatedProduct.Price.PriceWithVAT)">
1015 @Translate("product_listPrice", "Vejledende pris:") <span>@relatedListPrice.ToString("#.00")</span>
1016 </p>
1017 <p class="price">
1018 <template v-if="'@relatedIsCampaign' == 'True'">
1019 <span class="price-campaigntext">@Translate(basicPimPrefix + "Campaign_price", "Kampagnepris")</span>
1020 </template>
1021 <span itemprop="price" class="price-actual" content="@relatedPriceWithVat">
1022 @relatedPriceWithVat
1023 </span><span itemprop="priceCurrency" content="@Context.Currency.Code" class="hide"></span>
1024 </p>
1025 <p class="priceper">
1026 @Translate("product_pricePer", "Pris pr.") @unit.ToLower() @Translate("product_inclVat", "inkl. moms")
1027 </p>
1028 }
1029 <div class="basic_listview-delivery only-grid">
1030 @if (!string.IsNullOrEmpty(relatedABC) && relatedABC != "C")
1031 {
1032 if (Pageview.User != null)
1033 {
1034 <p class="stockstatus" alt="@relatedABC">
1035 @if (relatedABC == "A")
1036 {
1037 <svg>
1038 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
1039 </svg>
1040 <span>@Translate("ABC A Text", "Kort leveringstid")</span>
1041 }
1042 @if (relatedABC == "B")
1043 {
1044 <svg>
1045 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
1046 </svg>
1047 <span>@Translate("ABC B Text", "Forvent leveringstid")</span>
1048 }
1049 </p>
1050 }
1051 }
1052 @if (relatedMinPurchase > 1)
1053 {
1054 <p class="minQty">
1055 <svg>
1056 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#info-circle"></use>
1057 </svg>
1058 <span>
1059 @Translate("product_minPurchase", "Sælges kun i hele kolli á:") @relatedMinPurchase @relatedUnitId.ToLower()
1060 </span>
1061 </p>
1062
1063 }
1064 </div>
1065 <div class="basic_listview-buttons">
1066 <div class="@(B2C ? "b2c" : "b2b")">
1067 @if ((B2C || Pageview.User != null) && relatedProduct.VariantCount == 0)
1068 {
1069 <add-to-basket-rounding class="addtobasketrounding-plp"
1070 ref="basket"
1071 button-class="btn @actionColor btn-icon icon-only"
1072 product-id="@relatedProduct.Id"
1073 variant-id="@relatedProduct.VariantId"
1074 language-id="@relatedProduct.LanguageId"
1075 min-purchase="@relatedMinPurchase"
1076 escape-min-purch="@relatedEscapeMinPurch"
1077 :is-cool-down-product="@relatedIsCoolDown.ToString().ToLower()"
1078 :has-montage="false"
1079 :missing-variant="false"
1080 unit-of-measure="@relatedUnitId"
1081 :is-b2c="@B2C.ToString().ToLower()">
1082 </add-to-basket-rounding>
1083 }
1084 else
1085 {
1086 <a class="btn @actionColor" href="@url.PathAndQuery">
1087 @Translate("Show product", "Vis vare")
1088 </a>
1089 }
1090 </div>
1091 </div>
1092 </div>
1093 </footer>
1094 </article>
1095 }
1096 </div>
1097 </template>
1098 </section>
1099 }
1100 </section>
1101
1102
1103 }
1104
1105 <section class="basic_pim-specs" id="descspec">
1106 <div class="basic_pim-spec" style="min-width: 50%" id="desc">
1107 <h2>@Translate(basicPimPrefix + "Description", "Description")</h2>
1108 <div itemprop="description">
1109 @Model.LongDescription
1110 </div>
1111 </div>
1112 @if (listedSpecs.Any())
1113 {
1114 <div class="basic_pim-spec">
1115 <header id="spec">
1116 <h2>@Translate(basicPimPrefix + "Specifications", "Specifications")</h2>
1117 </header>
1118 <main>
1119 @if (isExtendedPdp)
1120 {
1121 <div>
1122 @if (!string.IsNullOrEmpty(documentationSecurityPaper.Value) || !string.IsNullOrEmpty(documentationProductPaper.Value) || !string.IsNullOrEmpty(documentationLink.Value))
1123 {
1124 <ul class="list-inline list-docs">
1125 @RenderDocumentation(documentationSecurityPaper)
1126 @RenderDocumentation(documentationProductPaper)
1127 @RenderDocumentation(documentationLink)
1128 </ul>
1129 }
1130 <div class="spec-list basic_filter">
1131 <div class="basic_filter-groups">
1132 @foreach (var item in specs.Where(a => extendedFields.Contains(a.Key)).GroupBy(x => x.Group2Order).OrderBy(x => x.Key))
1133 {
1134 var collapse = "v-b-toggle.collapse-" + item.Key;
1135
1136 <p class="basic_filter-group" area-expanded="false" @collapse>
1137 <strong style="font-size: 16px">@item.First().Group2</strong>
1138 <svg>
1139 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#chevron-right"></use>
1140 </svg>
1141 </p>
1142
1143 <b-collapse id="collapse-@item.Key" class="mt-2">
1144
1145 <ul class="list-unstyled list-tabled">
1146 @foreach (var group in item)
1147 {
1148 <li style="max-height: 30px">
1149 @{
1150 double result;
1151 string value = group.Value;
1152 if (double.TryParse(group.Value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out result) && value.Contains('.'))
1153 {
1154 value = value.Replace('.', ',');
1155 }
1156 <span style="font-weight: 500"><nobr>@group.Caption</nobr></span>
1157 <span>@value @group.Unit</span>
1158 }
1159 </li>
1160 }
1161 </ul>
1162
1163 </b-collapse>
1164 }
1165 </div>
1166 </div>
1167 </div>
1168
1169 }
1170 else
1171 {
1172 <div>
1173 @if (!string.IsNullOrEmpty(documentationSecurityPaper.Value) || !string.IsNullOrEmpty(documentationProductPaper.Value) || !string.IsNullOrEmpty(documentationLink.Value))
1174 {
1175 <ul class="list-inline list-docs">
1176 @RenderDocumentation(documentationSecurityPaper)
1177 @RenderDocumentation(documentationProductPaper)
1178 @RenderDocumentation(documentationLink)
1179 </ul>
1180 }
1181 <table class="table table-darker table-striped table-split">
1182 <tbody>
1183 @foreach (var specKey in listedSpecs)
1184 {
1185 var specValues = specs.GetAllByKey(specKey).ToList();
1186 var count = specValues.Count;
1187 <tr>
1188 <th>@specValues.First().Caption</th>
1189 <td>
1190 @if (count > 1)
1191 {
1192 <ul class="list-unstyled">
1193 @foreach (var spec in specValues)
1194 {
1195 bool valueBool;
1196 var value = spec.Value;
1197 if (bool.TryParse(value, out valueBool))
1198 {
1199 value = valueBool ? Translate("spec_yes", "Ja") : Translate("spec_no", "Nej");
1200 }
1201
1202 double result;
1203 if (double.TryParse(value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out result) && value.Contains('.'))
1204 {
1205 value = value.Replace('.', ',');
1206 }
1207
1208 <li>@value @spec.Unit</li>
1209 }
1210 </ul>
1211 }
1212 else
1213 {
1214 bool valueBool;
1215 var value = specValues.First().Value;
1216 if (bool.TryParse(value, out valueBool))
1217 {
1218 value = valueBool ? Translate("spec_yes", "Ja") : Translate("spec_no", "Nej");
1219 }
1220
1221 double result;
1222 if (double.TryParse(value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out result) && value.Contains('.'))
1223 {
1224 value = value.Replace('.', ',');
1225 }
1226
1227 <span>@value @specValues.First().Unit </span>
1228 }
1229 </td>
1230 </tr>
1231 }
1232 </tbody>
1233 </table>
1234 </div>
1235 if (!string.IsNullOrEmpty(energyLabel))
1236 {
1237 <div class="text-center wrap-energy" id="energylabel">
1238 <img src="@energyLabel" class="img-fluid energylabel" alt="@Model.Number"/><br/>
1239 <a href="@energyLabel" class="iconed">
1240 @Translate(basicPimPrefix + "Download energy mark", "Download")
1241 </a>
1242 </div>
1243 }
1244 }
1245 </main>
1246
1247 </div>
1248 if (isExtendedPdp && !string.IsNullOrEmpty(energyLabel))
1249 {
1250 <div class="basic_pim-spec text-center wrap-energy" style="max-width: 210px; margin-top: -20px" id="energylabel">
1251 @*<ul class="list-inline list-docs">
1252 <li class="list-inline-item">
1253 <a href="@energyLabel" class="iconed">
1254 <svg class="dark">
1255 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#file-pdf"></use>
1256 </svg>
1257 @Translate(basicPimPrefix + "Download energy mark", "Download")
1258 </a>
1259 </li>
1260 </ul>*@
1261 <img src="@energyLabel" class="img-fluid energylabel" alt="@Model.Number"/><br/>
1262 <a href="@energyLabel" class="iconed">
1263 @Translate(basicPimPrefix + "Download energy mark", "Download")
1264 </a>
1265 </div>
1266 }
1267 }
1268 </section>
1269 @if (isExtendedPdp)
1270 {
1271 @*<section class="basic_pim-features" id="features">
1272 <div class="fea">
1273 <h2>Features</h2>
1274 <ul class="list-unstyled list-features">
1275 <li>
1276 <img src="https://picsum.photos/210/140" alt="featureTitle" class="img-fluid" />
1277 <div>
1278 <h5>Madlavningstermometer</h5>
1279 <p>
1280 Universal termometer til brød, kager og alle typer kød. Med det integrerede madlavningstermometer kan du måle kernetemperaturen af din ret under tilberedningen.
1281 Så får du perfekte resultater hver gang. Madlavningstermometeret er ideel til både stegning og bagning. Visse modeller har madlavningstermometer med autosluk:
1282 Ovnen slukker automatisk, når indstillede kernetemperatur er opnået. Derved undgås unødig overtilberedning.
1283 </p>
1284 </div>
1285 </li>
1286 <li>
1287 <img src="https://picsum.photos/210/140" alt="featureTitle" class="img-fluid" />
1288 <div>
1289 <h5>Madlavningstermometer</h5>
1290 <p>
1291 Universal termometer til brød, kager og alle typer kød. Med det integrerede madlavningstermometer kan du måle kernetemperaturen af din ret under tilberedningen.
1292 Så får du perfekte resultater hver gang. Madlavningstermometeret er ideel til både stegning og bagning.
1293 </p>
1294 </div>
1295 </li>
1296 <li>
1297 <img src="https://picsum.photos/210/140" alt="featureTitle" class="img-fluid" />
1298 <div>
1299 <h5>Madlavningstermometer</h5>
1300 <p>
1301 Med det integrerede madlavningstermometer kan du måle kernetemperaturen af din ret under tilberedningen.
1302 Visse modeller har madlavningstermometer med autosluk:
1303 Ovnen slukker automatisk, når indstillede kernetemperatur er opnået. Derved undgås unødig overtilberedning.
1304 </p>
1305 </div>
1306 </li>
1307 </ul>
1308 </div>
1309 </section>*@
1310 }
1311 @if (!showRelatedFirst.Equals(true))
1312 {
1313 <section class="basic_view-related-wrap">
1314 @if (spareParts != null && spareParts.Any())
1315 {
1316 <section class="basic_listview basic_view-related">
1317 <template>
1318 <header>
1319 <h2>
1320 @Translate(basicPimPrefix + "Spare parts", "Spare parts")
1321 </h2>
1322 </header>
1323 <div class="basic_listview-grid related">
1324 @foreach (var sparePartRelation in spareParts)
1325 {
1326 var sparePart = sparePartRelation.Product;
1327 var url = urlService.GetProductUri(sparePart.Id, sparePart.VariantId);
1328 var sparePartUnitId = sparePart.GetUnitId();
1329 var sparePartProductImage = sparePart.GetPrimaryImage();
1330
1331 if (string.IsNullOrEmpty(sparePartProductImage))
1332 {
1333 sparePartProductImage = "/Files/Images/Default.png";
1334 }
1335 var sparePartListPrice = sparePart.GetListPrice();
1336 var sparePartMinPurchase = sparePart.GetMinPurchase();
1337 var sparePartEscapeMinPurch = sparePart.GetEscapeMinPurch();
1338 var sparePartABC = sparePart.GetAbcCategory();
1339 var sparePartDescriptions = sparePart.ProductFieldValues.Where(a => a.GetFieldName().Contains("Desc")).ToList();
1340 var sparePartIsCampaign = sparePart.IsCampaign();
1341 var sparePartPriceWithVat = sparePart.Price.PriceWithVAT.ToString("#.00");
1342 var sparePartAltText = sparePart.GetAltText();
1343 var sparePartIsCoolDown = sparePart.GetIsMainProductCoolDown();
1344
1345 <article class="basic_view-related--product" ppp="@sparePart.Id">
1346 <div class="innerwrap">
1347 <a href="@url.PathAndQuery">
1348 <figure>
1349 <img src="@Pageview.CdnWrap($"/Admin/Public/GetImage.ashx?Width=250&Height=130&Compression=85&Crop=5&Image={sparePartProductImage}")"
1350 alt="@sparePartAltText"
1351 itemprop="image"
1352 class="img-fluid"/>
1353 </figure>
1354 </a>
1355 <header>
1356 <div>
1357 <a href="@url.PathAndQuery" itemprop="url">
1358 <h1 itemprop="name">@sparePart.Name</h1>
1359 <p itemprop="description">
1360 @if (sparePartDescriptions.Any())
1361 {
1362 <span>
1363 @foreach (var i in sparePartDescriptions)
1364 {
1365 @i.Value
1366 }
1367 </span>
1368 }
1369 </p>
1370 </a>
1371 <p class="sku"><span itemprop="sku">@Translate(basicPimPrefix + "Product Number", "Product Number") @sparePart.Number</span></p>
1372 </div>
1373 </header>
1374 </div>
1375 <footer>
1376 <div class="basic_listview-pricing">
1377 @if (Pageview.User != null)
1378 {
1379 <async-price class-type="asyncprice-plp"
1380 default-price-without-vat="@sparePart.Price.PriceWithoutVAT"
1381 product-id="@sparePart.Id"
1382 :is-cool-down-product="@sparePartIsCoolDown.ToString().ToLower()"
1383 :variant-id="variantId"
1384 unit-of-measure="@sparePartUnitId"
1385 :list-price="@JsonConvert.SerializeObject(sparePartListPrice)"
1386 is-campaign="@sparePartIsCampaign"
1387 @@update-stock="setLiveStock">
1388 </async-price>
1389 }
1390 else if (B2C)
1391 {
1392 <p class="listprice" v-if="showListPrice(@sparePartListPrice, @sparePart.Price.PriceWithVAT)">
1393 @Translate("product_listPrice", "Vejledende pris:") <span>@sparePartListPrice.ToString("#.00")</span>
1394 </p>
1395 <p class="price">
1396 <template v-if="'@sparePartIsCampaign' == 'True'">
1397 <span class="price-campaigntext">@Translate(basicPimPrefix + "Campaign_price", "Kampagnepris")</span>
1398 </template>
1399 <span itemprop="price" class="price-actual" content="@sparePartPriceWithVat">
1400 @sparePartPriceWithVat
1401 </span><span itemprop="priceCurrency" content="@Context.Currency.Code" class="hide"></span>
1402 </p>
1403 <p class="priceper">
1404 @Translate("product_pricePer", "Pris pr.") @unit.ToLower() @Translate("product_inclVat", "inkl. moms")
1405 </p>
1406 }
1407 <div class="basic_listview-delivery only-grid">
1408 @if (!string.IsNullOrEmpty(sparePartABC))
1409 {
1410 if (Pageview.User != null)
1411 {
1412 <p class="stockstatus" alt="@sparePartABC">
1413 @if (sparePartABC == "A")
1414 {
1415 <svg>
1416 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
1417 </svg>
1418 <span>@Translate("ABC A Text", "Kort leveringstid")</span>
1419 }
1420 @if (sparePartABC == "B")
1421 {
1422 <svg>
1423 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
1424 </svg>
1425 <span>@Translate("ABC B Text", "Forvent leveringstid")</span>
1426 }
1427 </p>
1428 }
1429 }
1430 @if (sparePartMinPurchase > 1)
1431 {
1432 <p class="minQty">
1433 <svg>
1434 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#info-circle"></use>
1435 </svg>
1436 <span>
1437 @Translate("product_minPurchase", "Sælges kun i hele kolli á:") @sparePartMinPurchase @sparePartUnitId.ToLower()
1438 </span>
1439 </p>
1440
1441 }
1442 </div>
1443 <div class="basic_listview-buttons">
1444 <div class="@(B2C ? "b2c" : "b2b")">
1445 @if ((B2C || Pageview.User != null) && sparePart.VariantCount == 0)
1446 {
1447 <add-to-basket-rounding class="addtobasketrounding-plp"
1448 button-class="btn @actionColor btn-icon icon-only"
1449 product-id="@sparePart.Id"
1450 variant-id="@sparePart.VariantId"
1451 language-id="@sparePart.LanguageId"
1452 min-purchase="@sparePartMinPurchase"
1453 escape-min-purch="@sparePartEscapeMinPurch"
1454 :is-cool-down-product="@sparePartIsCoolDown.ToString().ToLower()"
1455 :has-montage="false"
1456 :missing-variant="false"
1457 unit-of-measure="@sparePartUnitId"
1458 :is-b2c="@B2C.ToString().ToLower()">
1459 </add-to-basket-rounding>
1460 }
1461 else
1462 {
1463 <a class="btn @actionColor" href="@url.PathAndQuery">
1464 @Translate("Show product", "Vis vare")
1465 </a>
1466 }
1467 </div>
1468 </div>
1469 </div>
1470 </footer>
1471 </article>
1472 }
1473 </div>
1474 </template>
1475 </section>
1476 }
1477
1478 @if (relatedProducts != null && relatedProducts.Any())
1479 {
1480 <section class="basic_listview basic_view-related" id="related-products">
1481 <template>
1482 <header>
1483 <h2>
1484 @Translate(basicPimPrefix + "Related Products", "Related Products")
1485 </h2>
1486 </header>
1487 <div class="basic_listview-grid related">
1488 @foreach (var related in relatedProducts)
1489 {
1490 var relatedProduct = related.Product;
1491 var url = urlService.GetProductUri(relatedProduct.Id, relatedProduct.VariantId);
1492 var relatedUnitId = relatedProduct.GetUnitId();
1493 var relatedProductImage = relatedProduct.GetPrimaryImage();
1494
1495 if (string.IsNullOrEmpty(relatedProductImage))
1496 {
1497 relatedProductImage = "/Files/Images/Default.png";
1498 }
1499 var relatedListPrice = relatedProduct.GetListPrice();
1500 var relatedMinPurchase = relatedProduct.GetMinPurchase();
1501 var relatedEscapeMinPurch = relatedProduct.GetEscapeMinPurch();
1502 var relatedABC = relatedProduct.GetAbcCategory();
1503 var relatedProductDescriptions = relatedProduct.ProductFieldValues.Where(a => a.GetFieldName().Contains("Desc")).ToList();
1504 var relatedIsCampaign = relatedProduct.IsCampaign();
1505 var relatedPriceWithVat = relatedProduct.Price.PriceWithVAT.ToString("#.00");
1506 var relatedAltText = relatedProduct.GetAltText();
1507 var relatedProductIsCoolDown = relatedProduct.GetIsMainProductCoolDown();
1508
1509 <article class="basic_view-related--product" ppp="@relatedProduct.Id">
1510 <div class="innerwrap">
1511 <a href="@url.PathAndQuery">
1512 <figure>
1513 <img src="@Pageview.CdnWrap($"/Admin/Public/GetImage.ashx?Width=250&Height=130&Compression=85&Crop=5&Image={relatedProductImage}")"
1514 alt="@relatedAltText"
1515 itemprop="image"
1516 class="img-fluid"/>
1517 </figure>
1518 </a>
1519 <header>
1520 <div>
1521 <a href="@url.PathAndQuery" itemprop="url">
1522 <h1 itemprop="name">@relatedProduct.Name</h1>
1523 <p itemprop="description">
1524 @if (relatedProductDescriptions.Any())
1525 {
1526 <span>
1527 @foreach (var i in relatedProductDescriptions)
1528 {
1529 @i.Value
1530 }
1531 </span>
1532 }
1533 </p>
1534 </a>
1535 <p class="sku"><span itemprop="sku">@Translate(basicPimPrefix + "Product Number", "Product Number") @relatedProduct.Number</span></p>
1536
1537 <p>
1538 @{
1539 foreach (var logo in relatedProduct.GetSustainableLogos())
1540 {
1541 if (!string.IsNullOrEmpty(logo))
1542 {
1543 var path = "/Files/Images/Graphics/" + logo + ".png";
1544 <img src="@path" class="img-fluid" style="max-height: 40px; margin-right: 5px"/>
1545 }
1546 }
1547 }
1548 </p>
1549 </div>
1550 </header>
1551 </div>
1552 <footer>
1553 <div class="basic_listview-pricing">
1554 @if (Pageview.User != null)
1555 {
1556 <async-price class-type="asyncprice-plp"
1557 default-price-without-vat="@relatedProduct.Price.PriceWithoutVAT"
1558 product-id="@relatedProduct.Id"
1559 :variant-id="variantId"
1560 unit-of-measure="@relatedUnitId"
1561 :is-cool-down-product="@relatedProductIsCoolDown.ToString().ToLower()"
1562 :list-price="@JsonConvert.SerializeObject(relatedListPrice)"
1563 is-campaign="@relatedIsCampaign"
1564 @@update-stock="setLiveStock">
1565 </async-price>
1566 }
1567 else if (B2C)
1568 {
1569 <p class="listprice" v-if="showListPrice(@relatedListPrice, @relatedProduct.Price.PriceWithVAT)">
1570 @Translate("product_listPrice", "Vejledende pris:") <span>@relatedListPrice.ToString("#.00")</span>
1571 </p>
1572 <p class="price">
1573 <template v-if="'@relatedIsCampaign' == 'True'">
1574 <span class="price-campaigntext">@Translate(basicPimPrefix + "Campaign_price", "Kampagnepris")</span>
1575 </template>
1576 <span itemprop="price" class="price-actual" content="@relatedPriceWithVat">
1577 @relatedPriceWithVat
1578 </span><span itemprop="priceCurrency" content="@Context.Currency.Code" class="hide"></span>
1579 </p>
1580 <p class="priceper">
1581 @Translate("product_pricePer", "Pris pr.") @unit.ToLower() @Translate("product_inclVat", "inkl. moms")
1582 </p>
1583 }
1584 <div class="basic_listview-delivery only-grid">
1585 @if (!string.IsNullOrEmpty(relatedABC) && relatedABC != "C")
1586 {
1587 if (Pageview.User != null)
1588 {
1589 <p class="stockstatus" alt="@relatedABC">
1590 @if (relatedABC == "A")
1591 {
1592 <svg>
1593 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
1594 </svg>
1595 <span>@Translate("ABC A Text", "Kort leveringstid")</span>
1596 }
1597 @if (relatedABC == "B")
1598 {
1599 <svg>
1600 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#truck"></use>
1601 </svg>
1602 <span>@Translate("ABC B Text", "Forvent leveringstid")</span>
1603 }
1604 </p>
1605 }
1606 }
1607 @if (relatedMinPurchase > 1)
1608 {
1609 <p class="minQty">
1610 <svg>
1611 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#info-circle"></use>
1612 </svg>
1613 <span>
1614 @Translate("product_minPurchase", "Sælges kun i hele kolli á:") @relatedMinPurchase @relatedUnitId.ToLower()
1615 </span>
1616 </p>
1617
1618 }
1619 </div>
1620 <div class="basic_listview-buttons">
1621 <div class="@(B2C ? "b2c" : "b2b")">
1622 @if ((B2C || Pageview.User != null) && relatedProduct.VariantCount == 0)
1623 {
1624 <add-to-basket-rounding class="addtobasketrounding-plp"
1625 ref="basket"
1626 button-class="btn @actionColor btn-icon icon-only"
1627 product-id="@relatedProduct.Id"
1628 variant-id="@relatedProduct.VariantId"
1629 language-id="@relatedProduct.LanguageId"
1630 min-purchase="@relatedMinPurchase"
1631 escape-min-purch="@relatedEscapeMinPurch"
1632 :is-cool-down-product="@relatedProductIsCoolDown.ToString().ToLower()"
1633 :has-montage="false"
1634 :missing-variant="false"
1635 unit-of-measure="@relatedUnitId"
1636 :is-b2c="@B2C.ToString().ToLower()">
1637 </add-to-basket-rounding>
1638 }
1639 else
1640 {
1641 <a class="btn @actionColor" href="@url.PathAndQuery">
1642 @Translate("Show product", "Vis vare")
1643 </a>
1644 }
1645 </div>
1646 </div>
1647 </div>
1648 </footer>
1649 </article>
1650 }
1651 </div>
1652 </template>
1653 </section>
1654 }
1655 </section>
1656
1657
1658 }
1659
1660 </div>
1661 </product-details-simple-pim>
1662 @helper RenderDocumentation(ProductSpecification productSpecification)
1663 {
1664 if (string.IsNullOrEmpty(productSpecification.Value))
1665 {
1666 return;
1667 }
1668 <li class="list-inline-item">
1669 <a href="@productSpecification.Value" class="iconed">
1670 <svg class="dark">
1671 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/Files/dist/icons/icons.svg#file-pdf"></use>
1672 </svg>
1673 @productSpecification.Key
1674 </a>
1675 </li>
1676 }
1677