Error executing template "Designs/Default/eCom/ProductCatalog/Product.cshtml" System.InvalidOperationException: Fejl ved parsing af NAV response: There is an error in XML document (1, 1). ---> System.InvalidOperationException: There is an error in XML document (1, 1). ---> System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1. at System.Xml.XmlTextReaderImpl.Throw(Exception e) at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace() at System.Xml.XmlTextReaderImpl.ParseDocumentContent() at System.Xml.XmlReader.MoveToContent() at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderNavWebshopPricesResponse.Read4_WebshopPrices() --- End of inner exception stack trace --- at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader) at Custom.Api.Prices.Helpers.NavPriceParsingHelper.DeserializeWebshopPrices(String webshopPricesXml) in D:\a\1\s\Custom.Api\Prices\Helpers\NavPriceParsingHelper.cs:line 50 at Custom.Api.Prices.Helpers.NavPriceParsingHelper.ParseSoapResponse(String soapResponse) in D:\a\1\s\Custom.Api\Prices\Helpers\NavPriceParsingHelper.cs:line 31 --- End of inner exception stack trace --- at Custom.Api.Prices.Helpers.NavPriceParsingHelper.ParseSoapResponse(String soapResponse) in D:\a\1\s\Custom.Api\Prices\Helpers\NavPriceParsingHelper.cs:line 36 at Custom.Api.Services.NavPriceService.GetPrices(String shopId, String customerNumber, IEnumerable`1 generalProductIds, Boolean forceRefresh) in D:\a\1\s\Custom.Api\Prices\Services\NavPriceService.cs:line 74 at Custom.Api.Services.NavPriceService.GetSinglePrice(String shopId, String customerNumber, String productId, Boolean forceRefresh) in D:\a\1\s\Custom.Api\Prices\Services\NavPriceService.cs:line 149 at Gasa.ProductInformation.ProductInformation..ctor(Product product, String customerNumber) in C:\Repos\GasaGroup-Dynamicweb\Gasa.ProductInformation\ProductInformation.cs:line 22 at CompiledRazorTemplates.Dynamic.RazorEngine_25e9178283cb40c0907876c8e2936995.Execute() in E:\Dynamicweb.net\Solutions\Webshop\Files\Templates\Designs\Default\eCom\ProductCatalog\Product.cshtml:line 706 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.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits ViewModelTemplate<ProductViewModel> 2 @using System.Web; 3 @using Dynamicweb; 4 @using Dynamicweb.Core; 5 @using Dynamicweb.Environment; 6 @using Dynamicweb.Rendering; 7 @using Dynamicweb.Ecommerce.ProductCatalog; 8 @using System.Linq; 9 @using Gasa.ProductInformation; 10 @using Gasa.PriceInformation; 11 @using Gasa.ProductInformation.Helpers; 12 @using Dynamicweb.Ecommerce.Prices; 13 @using Gasa.Calendar; 14 @using Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites 15 16 @using Dynamicweb.Ecommerce.Orders; 17 @using System.Globalization; 18 @using Dynamicweb.Security.UserManagement; 19 @using Dynamicweb.Security.UserManagement.Common.CustomFields; 20 @using Dynamicweb; 21 @using Dynamicweb.Core; 22 @using Dynamicweb.Environment; 23 @using Dynamicweb.Environment.Helpers; 24 @using Dynamicweb.Rendering; 25 @using Dynamicweb.Ecommerce.ProductCatalog; 26 @using System.Linq; 27 @using Gasa.ProductInformation; 28 @using Gasa.Calendar; 29 30 @* Note that this file will be inserted directly into another one by Dynamicweb IncludeFile 31 before evaluating the Razor code, so keep the syntax right *@ 32 33 34 @* global functions *@ 35 36 @functions { 37 bool checkIfFileExists(string imgURL) 38 { 39 return System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath(imgURL)); 40 } 41 string FormatDiameter(string value) 42 { 43 if (string.IsNullOrEmpty(value)) 44 { 45 return value; 46 } 47 48 Decimal d; 49 if (Decimal.TryParse(value, out d)) 50 { 51 return Converter.ToDouble(value).ToString("0.0", Dynamicweb.Frontend.PageView.Current().Area.CultureInfo.NumberFormat); 52 //return d.ToString("0.0", Base.GetCulture(true)); 53 } 54 55 return value; 56 } 57 58 string FormatPrice(string value) 59 { 60 if (string.IsNullOrEmpty(value)) 61 { 62 return value; 63 } 64 65 Decimal d; 66 if (Decimal.TryParse(value, out d)) 67 { 68 return Converter.ToDouble(value).ToString("0.00", Dynamicweb.Frontend.PageView.Current().Area.CultureInfo.NumberFormat); 69 } 70 71 return value; 72 } 73 74 string AvailableDeliveryDay(int leadDays) 75 { 76 DateTime today = DateTime.Now.Date; 77 DateTime availableDate = today; 78 DateTime deliveryDate = CalenderHelper.ParseDateTime(Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime").Value); 79 TimeSpan daysDifference = deliveryDate - today; 80 CultureInfo localLanguage = System.Threading.Thread.CurrentThread.CurrentCulture; 81 string result; 82 83 int leadWeekendDays = 0; 84 85 86 // check how many weekends within lead days 87 for (var i = 0; i < leadDays; i++) 88 { 89 if (availableDate.AddDays(i).DayOfWeek == DayOfWeek.Saturday) 90 { 91 leadWeekendDays++; 92 } 93 else if (availableDate.AddDays(i).DayOfWeek == DayOfWeek.Sunday) 94 { 95 leadWeekendDays++; 96 } 97 } 98 99 // check how many weekends after lead weekdays 100 for (var i = 0; i < leadWeekendDays; i++) 101 { 102 if (availableDate.AddDays(leadDays + i).DayOfWeek == DayOfWeek.Saturday) 103 { 104 leadWeekendDays++; 105 } 106 else if (availableDate.AddDays(leadDays + i).DayOfWeek == DayOfWeek.Sunday) 107 { 108 leadWeekendDays++; 109 } 110 } 111 112 var leadDaysTotal = leadWeekendDays + leadDays; 113 114 availableDate = availableDate.AddDays(leadDaysTotal); 115 116 if (daysDifference.TotalDays >= leadDaysTotal && availableDate <= deliveryDate) 117 { 118 result = null; 119 } 120 else 121 { 122 result = availableDate.ToString("dd-MM-yyyy", localLanguage); 123 } 124 //result=daysDifference.TotalDays.ToString(); 125 return result; 126 } 127 128 /* 129 bool EnableEditing() 130 { 131 return EnableEditableBarcode(); 132 } 133 */ 134 135 bool? _enableManufacturerPage; 136 bool EnableManufacturerPage() 137 { 138 if (!_enableManufacturerPage.HasValue) 139 { 140 if (Pageview.Page.PropertyItem != null && Converter.ToBoolean(Pageview.Page.PropertyItem["EnableManufacturer"])) 141 { 142 _enableManufacturerPage = true; 143 } 144 else 145 { 146 _enableManufacturerPage = false; 147 } 148 } 149 return _enableManufacturerPage.Value; 150 } 151 152 ///* generic validation of custom user fields */ 153 //bool? returnCustomUserFieldValidation(string CustomerUserFieldString) 154 //{ 155 // return GetCustomUserField<bool>(user, CustomerUserFieldString); 156 //} 157 158 159 bool? _displayPricesInclVat; 160 bool DisplayPricesInclVat() 161 { 162 if (!_displayPricesInclVat.HasValue) 163 { 164 _displayPricesInclVat = GetCustomUserField<bool>("AccessUser_DisplayPricesInclVat"); 165 } 166 return _displayPricesInclVat.Value; 167 } 168 169 bool? _enableEditableItemNumber; 170 bool EnableEditableItemNumber() 171 { 172 if (!_enableEditableItemNumber.HasValue) 173 { 174 _enableEditableItemNumber = GetCustomUserField<bool>("AccessUser_EnableEditableItemNumber"); 175 } 176 return _enableEditableItemNumber.Value; 177 } 178 179 //AccessUser_EnableManufacturerFiltering 180 bool? _enableManufacturerFiltering; 181 bool EnableManufacturerFiltering(bool chkEnableManufacturerPageEnableManufacturerPage = true) 182 { 183 if (chkEnableManufacturerPageEnableManufacturerPage && !EnableManufacturerPage()) 184 return false; 185 186 if (!_enableManufacturerFiltering.HasValue) 187 { 188 _enableManufacturerFiltering = GetCustomUserField<bool>("AccessUser_EnableManufacturerFiltering"); 189 } 190 return _enableManufacturerFiltering.Value; 191 } 192 193 bool? _enableCustomerItemNumber; 194 bool EnableCustomerItemNumber() 195 { 196 if (!_enableCustomerItemNumber.HasValue) 197 { 198 _enableCustomerItemNumber = GetCustomUserField<bool>("AccessUser_EnableCustomerItemNumber"); 199 } 200 return _enableCustomerItemNumber.Value; 201 } 202 203 bool? _enableEditableRetailPrice; 204 bool EnableEditableRetailPrice() 205 { 206 if (!_enableEditableRetailPrice.HasValue) 207 { 208 _enableEditableRetailPrice = GetCustomUserField<bool>("AccessUser_EnableEditableRetailPrice"); 209 } 210 return _enableEditableRetailPrice.Value; 211 } 212 213 bool? _enableEditableBarcode; 214 bool EnableEditableBarcode() 215 { 216 if (!_enableEditableBarcode.HasValue) 217 { 218 _enableEditableBarcode = GetCustomUserField<bool>("AccessUser_EnableEditableBarcode"); 219 } 220 return _enableEditableBarcode.Value; 221 } 222 223 bool? _enableCustomerRetailPrice; 224 bool EnableCustomerRetailPrice() 225 { 226 if (!_enableCustomerRetailPrice.HasValue) 227 { 228 _enableCustomerRetailPrice = GetCustomUserField<bool>("AccessUser_EnableCustomerRetailPrice"); 229 } 230 return _enableCustomerRetailPrice.Value; 231 } 232 233 bool? _enableCustomerBarcode; 234 bool EnableCustomerBarcode() 235 { 236 if (!_enableCustomerBarcode.HasValue) 237 { 238 _enableCustomerBarcode = GetCustomUserField<bool>("AccessUser_EnableCustomerBarcode"); 239 } 240 return _enableCustomerBarcode.Value; 241 242 } 243 244 bool? _enableComments; 245 bool EnableComments() 246 { 247 if (!_enableComments.HasValue) 248 { 249 _enableComments = GetCustomUserField<bool>("AccessUser_EnableCommentOnLine"); 250 } 251 return _enableComments.Value; 252 } 253 254 bool? _enableMinimumCCQuantity; 255 bool EnableMinimumCCQuantity() 256 { 257 if (!_enableMinimumCCQuantity.HasValue) 258 { 259 _enableMinimumCCQuantity = GetCustomUserField<bool>("AccessUser_EnableMinimumCCQuantity"); 260 } 261 return _enableMinimumCCQuantity.Value; 262 } 263 bool? _enableFullCCCheck; 264 bool EnableFullCCCheck() 265 { 266 if (!_enableFullCCCheck.HasValue) 267 { 268 _enableFullCCCheck = GetCustomUserField<bool>("AccessUser_EnableFullCCCheck"); 269 } 270 return _enableFullCCCheck.Value; 271 } 272 273 bool? _enableDisplayGrossMargin; 274 bool EnableDisplayOfGrossMargin() 275 { 276 if (DisablePrices()) 277 return false; 278 279 if (!_enableDisplayGrossMargin.HasValue) 280 { 281 _enableDisplayGrossMargin = GetCustomUserField<bool>("AccessUser_DisplayGrossMargin"); 282 } 283 return _enableDisplayGrossMargin.Value; 284 } 285 286 string GetGrossMargin(double retailPrice, double salesPrice) 287 { 288 var resultValue = ((retailPrice - salesPrice) * 100) / retailPrice; 289 return Converter.ToString(Math.Round(resultValue, 2)) + "%"; 290 } 291 292 293 double? _minimumCCQuantity; 294 double MinimumCCQuantity(string flag = "") 295 { 296 if (!_minimumCCQuantity.HasValue) 297 { 298 _minimumCCQuantity = GetCustomUserField<double>("AccessUser_MinimumCCQuantity" + flag.ToUpper()); 299 } 300 return _minimumCCQuantity.Value; 301 } 302 303 bool? _disablePrices; 304 bool DisablePrices() 305 { 306 if (!_disablePrices.HasValue) 307 { 308 _disablePrices = GetCustomUserField<bool>("AccessUser_DisablePrices"); 309 } 310 return _disablePrices.Value; 311 } 312 313 double? _fullCCCheckDeviation; 314 double FullCCCheckDeviation() 315 { 316 if (!_fullCCCheckDeviation.HasValue) 317 { 318 _fullCCCheckDeviation = GetCustomUserField<double>("AccessUser_FullCCCheckDeviation"); 319 } 320 321 return _fullCCCheckDeviation.Value; 322 } 323 324 //bool HasReachedMinimumQuantity() 325 //{ 326 // if (!EnableMinimumCCQuantity()) 327 // { 328 // return true; 329 // } 330 331 // var orderlinesGroupByCode = GetLoop("OrderLines").GroupBy(o => o.GetString("Ecom:Product:Field.NavCompanyCode")) 332 // .Select(o => new { 333 // Flag = o.FirstOrDefault().GetString("Ecom:Product:Field.NavCompanyCode"), 334 // CCRate = o.Sum(f => f.GetInteger("Ecom:Order:OrderLine.Quantity") * f.GetDouble("CustomerSpecificProductInformation.CCRate")) 335 // }); 336 337 // if (orderlinesGroupByCode.Count() == orderlinesGroupByCode.Where(o => o.CCRate >= MinimumCCQuantity(o.Flag)).Count()) 338 // { 339 // return true; 340 // } 341 342 // return false; 343 //} 344 345 //bool HasPassedFullCCCheckDeviationCheck() 346 //{ 347 // if (!EnableFullCCCheck()) 348 // { 349 // return true; 350 // } 351 352 // var orderlinesGroupByCode = GetLoop("OrderLines").GroupBy(o => o.GetString("Ecom:Product:Field.NavCompanyCode")) 353 // .Select(o => new { CCRate = o.Sum(f => f.GetInteger("Ecom:Order:OrderLine.Quantity") * f.GetDouble("CustomerSpecificProductInformation.CCRate")) }); 354 355 // if (orderlinesGroupByCode.Count() == orderlinesGroupByCode.Where(o => (o.CCRate % 1) == 0 || LessOrEqual((o.CCRate % 1), FullCCCheckDeviation()) || LessOrEqual(Math.Abs(1 - (o.CCRate % 1)), FullCCCheckDeviation())).Count()) 356 // { 357 // return true; 358 // } 359 360 // return false; 361 //} 362 363 //AE: Workaround for comparing doubles 364 bool LessOrEqual(double d1, double d2) 365 { 366 return d1 < d2 || Math.Abs(d1 - d2) <= 0.0000001; 367 } 368 369 /* 370 bool DisableComments() 371 { 372 User user = User.get_Current(PagePermissionLevels.Frontend); 373 374 return GetCustomField<bool>(user, "AccessUser_EnableCommentOnLine"); 375 } 376 */ 377 //static T GetCustomOrderLineField<T>(OrderLine orderLine, string customSystemFieldName) 378 //{ 379 // OrderLineFieldValue myFieldValue = 380 // orderLine.OrderLineFieldValues.FirstOrDefault(cfv => cfv.OrderLineFieldSystemName == customSystemFieldName); 381 382 // if (myFieldValue != null) 383 // { 384 // return (T)Convert.ChangeType(myFieldValue.Value, typeof(T)); 385 // } 386 387 // // Return default(T) which means you'll return null 388 // return default(T); 389 //} 390 391 //static T GetCustomOrderLineField<T>(LoopItem orderLine, string customSystemFieldName) 392 //{ 393 // var template = 394 // orderLine.GetLoop("Order.OrderLineFields").FirstOrDefault(o => o.GetString("Ecom:Order:OrderLine.OrderLineField.SystemName") == customSystemFieldName); 395 396 // if (template != null) 397 // { 398 // return (T)Convert.ChangeType(template.GetValue("Ecom:Order:OrderLine.OrderLineField.Value.Clean"), typeof(T)); 399 // } 400 401 // // Return default(T) which means you'll return null 402 // return default(T); 403 //} 404 405 Dynamicweb.Security.UserManagement.User _user = null; 406 T GetCustomUserField<T>(string customSystemFieldName) 407 { 408 if (_user == null) 409 { 410 _user = Dynamicweb.Security.UserManagement.User.GetCurrentFrontendUser(); 411 } 412 413 if (_user != null) 414 { 415 CustomFieldValue myFieldValue = _user.CustomFieldValues.FirstOrDefault(cfv => cfv.CustomField.SystemName == customSystemFieldName); 416 417 try 418 { 419 if (myFieldValue != null) 420 { 421 return (T)Convert.ChangeType(myFieldValue.Value, typeof(T)); 422 } 423 } 424 catch (Exception) 425 { 426 return default(T); 427 } 428 } 429 430 // Return default(T) which means you'll return null 431 return default(T); 432 } 433 434 435 ICollection<Dynamicweb.Ecommerce.Orders.OrderLineField> SortOrderLineFields(ICollection<Dynamicweb.Ecommerce.Orders.OrderLineField> loop) 436 { 437 return loop 438 .OrderByDescending(o => o.SystemName == "OrderLineComment") 439 .ThenByDescending(o => o.SystemName == "OrderLineRetailPrice") 440 .ThenByDescending(o => o.SystemName == "OrderLineItemNumber") 441 .ThenByDescending(o => o.SystemName == "OrderLineEAN").ToList(); 442 } 443 444 bool IsInCart(ProductViewModel product) 445 { 446 var cart = Dynamicweb.Ecommerce.Common.Context.Cart; 447 if (cart != null) 448 { 449 foreach (var ol in cart.OrderLines) 450 { 451 if (ol.ProductId == product.Id) 452 { 453 return true; 454 } 455 } 456 } 457 return false; 458 } 459 460 //string GetProductInfoValue(ProductInformation productInfo, string key) 461 //{ 462 // if (productInfo.Values != null) 463 // { 464 // object value; 465 // if (productInfo.Values.TryGetValue(key, out value)) 466 // { 467 // if (!string.IsNullOrEmpty(Converter.ToString(value))) 468 // { 469 // return Converter.ToString(value); 470 // } 471 // } 472 // } 473 // return string.Empty; 474 //} 475 476 } 477 478 479 @* html helpers section *@ 480 481 482 @helper renderToolTip() 483 { 484 var jsSuggestionStock = "<span class='js-suggestion-stock'></span>"; 485 <div class="hide js-tooltip-content quantity-tooltip-content"> 486 <h4 class="title"> 487 @Translate("Smartpage:Product.PackageSizeCeiled", "Antallet vil blive opskrevet til") <span class="js-package-size-quantity"></span> <a href="#" data-toggle="tooltip" data-placement="top" class="js-package-size-single package-size-single" title='@Translate("Smartpage:Product.PackageSizeCeiled.singleProduct.Text", "Det ønskede antal vare stemmer ikke overens med kollistørrelsen")'><i class="glyphicon glyphicon-info-sign"></i></a> 488 </h4> 489 <button class="btn btn-xs btn-info js-package-size-cancel" data-toggle="clickover"><i class="glyphicon glyphicon-remove"></i></button> 490 <button class="btn btn-xs btn-primary js-package-size-ok" data-toggle="clickover"><i class="glyphicon glyphicon-ok"></i></button> 491 </div> 492 493 <div class="hide js-tooltip-smaller-quantity quantity-tooltip-content"> 494 <h4 class="title"> 495 @Translate("Smartpage:Popover.OutOfStockText.LessQuantity", "Varen blev ikke tilføjet til kurven, forsøg med et mindre antal") 496 </h4> 497 <button class="btn btn-xs btn-info js-close-out-of-stock" data-toggle="clickover"><i class="glyphicon glyphicon-ok"></i></button> 498 </div> 499 500 <div class="hide js-tooltip-stock-content quantity-tooltip-content"> 501 <h4 class="title"> 502 @Translate("Smartpage:Popover.OutOfStockText", "Varen blev ikke tilføjet til kurven, fordi vi har ikke flere på lager") 503 </h4> 504 <button class="btn btn-xs btn-info js-close-out-of-stock" data-toggle="clickover"><i class="glyphicon glyphicon-ok"></i></button> 505 </div> 506 507 <div class="hide js-tooltip-stock-suggestion quantity-tooltip-content"> 508 <h4 class="title"> 509 @Translate("Smartpage:Popover.OutOfStockText.Suggestion", String.Format("Vi har kun {0} på lager. Vil du ændre antal?", jsSuggestionStock)) 510 </h4> 511 <button class="btn btn-xs btn-info js-cancel-out-of-stock" data-toggle="clickover"><i class="glyphicon glyphicon-remove"></i></button> 512 <button class="btn btn-xs btn-info js-accept-out-of-stock" data-toggle="clickover"><i class="glyphicon glyphicon-ok"></i></button> 513 </div> 514 } 515 516 517 @helper AddedToCart(ProductViewModel i, string cssClass) 518 { 519 var cart = Dynamicweb.Ecommerce.Common.Context.Cart; 520 string cssIsInCart = !IsInCart(i) ? "hide" : ""; 521 522 <span class='label label-success js-in-cart in-cart @cssClass @cssIsInCart'><i class="glyphicon glyphicon-shopping-cart"></i> @Translate("Smartpage:AddedInCart", "added")</span> 523 } 524 525 @helper SingleAddedToCart(ProductViewModel product) 526 { 527 string cssIsInCart = !IsInCart(product) ? "hide" : ""; 528 <span class='label label-success in-cart js-in-cart product @cssIsInCart'><i class="glyphicon glyphicon-shopping-cart"></i> @Translate("Smartpage:AddedInCart", "added")</span> 529 } 530 531 @helper SingleStockStatus(ProductViewModel product) 532 { 533 bool outOfStock = product.StockLevel <= 0; 534 bool isServiceProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, product.VariantId, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).Type == Dynamicweb.Ecommerce.Products.ProductType.Service; 535 536 <div class='stock-status single-product'> 537 @if (outOfStock && !isServiceProduct) 538 { 539 <span class="label label-danger js-out-of-stock">@Translate("Smartpage:OutOfStock", "Ikke på lager")</span> 540 } 541 </div> 542 } 543 544 @helper ListStockStatus(ProductViewModel i, string currentViewMode) 545 { 546 bool outOfStock = i.StockLevel <= 0; 547 bool isServiceProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(i.Id, i.VariantId, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).Type == Dynamicweb.Ecommerce.Products.ProductType.Service; 548 549 <div class='stock-status @currentViewMode'> 550 @if (outOfStock && !isServiceProduct) 551 { 552 <span class="label label-danger js-out-of-stock">@Translate("Smartpage:OutOfStock", "Ikke på lager")</span> 553 } 554 @if (!isServiceProduct && !outOfStock) { 555 <span class='label label-success'>@i.StockLevel @Translate("GASA.LeftOnStock", "left on stock")</span> 556 } 557 </div> 558 } 559 560 561 @helper PricesWithVATStatus(string positionCSS) { 562 if (DisplayPricesInclVat()) 563 { 564 <p class='vat-message text-muted text-center @positionCSS'>@Translate("Smartpage:PricesIncludeVAT.Message", "Alle priser er inkl. Moms")</p> 565 } 566 else 567 { 568 <p class='vat-message text-muted text-center @positionCSS'>@Translate("Smartpage:PricesDoNotIncludeVAT.Message", "Alle priser er ekskl. Moms")</p> 569 } 570 } 571 572 @helper RenderManufacturer(string manufacturerId, string manufacturerName, string manufacturerWebsiteUrl) 573 { 574 if (EnableManufacturerFiltering()) 575 { 576 var name = manufacturerName + "/" + manufacturerId; 577 if (!string.IsNullOrEmpty(manufacturerWebsiteUrl)) 578 { 579 <a class="manufacturer-info-link" href="@manufacturerWebsiteUrl" target="_blank">@name</a> 580 } 581 else 582 { 583 <span class="manufacturer-info">@name</span> 584 } 585 } 586 } 587 @using Dynamicweb.Ecommerce.Orders; 588 @using System.Globalization; 589 @using Dynamicweb.Security.UserManagement; 590 @using Dynamicweb.Security.UserManagement.Common.CustomFields; 591 @using Dynamicweb; 592 @using Dynamicweb.Core; 593 @using Dynamicweb.Environment; 594 @using Dynamicweb.Environment.Helpers; 595 @using Dynamicweb.Rendering; 596 @using Dynamicweb.Ecommerce.ProductCatalog; 597 @using System.Linq; 598 @using Gasa.ProductInformation; 599 @using Gasa.Calendar; 600 601 @* Note that this file will be inserted directly into another one by Dynamicweb IncludeFile 602 before evaluating the Razor code, so keep the syntax right *@ 603 604 @* Favorite Helper *@ 605 606 @helper FavoriteHelper(ProductViewModel pvm, string displayType, bool isSimpleAddToCartSection = false) 607 { 608 Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites.FavoriteListService favoriteListService = new Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites.FavoriteListService(); 609 var user = Dynamicweb.Security.UserManagement.User.GetCurrentFrontendUser(); 610 string pageId = Dynamicweb.Context.Current.Request["ID"]; 611 string currentPrice = pvm.Price.PriceFormatted != pvm.PriceBeforeDiscount.PriceFormatted ? pvm.Price.PriceFormatted : pvm.PriceBeforeDiscount.PriceFormatted; 612 613 string favoriteIcon = "fas fa-"; 614 string favoriteOutlineIcon = "fal fa-"; 615 int modifyFavoriteListPage = GetPageIdByNavigationTag("ModifyFavoriteListPage"); 616 617 if (user != null && modifyFavoriteListPage > 0) 618 { 619 string favoriteId = "Favorite" + pvm.Id + (isSimpleAddToCartSection ? "simple" : ""); 620 var customerCenterLists = Dynamicweb.Ecommerce.CustomerCenter.CustomerProductList.GetListByCustomerId(user.ID); 621 622 // This page needs to be used since View pvm catalogue can't handle adding to favorites 623 // Use standard product catalogue instead 624 string favoriteButtonCss = ""; 625 626 switch (displayType) 627 { 628 case "product-detail": 629 favoriteButtonCss = "favorite-button-product-detail"; 630 break; 631 case "photo-view": 632 favoriteButtonCss = "favorite-button-photo-view"; 633 break; 634 case "tiles-view": 635 favoriteButtonCss = "favorite-button-tiles-view"; 636 break; 637 case "list-view": 638 favoriteButtonCss = "favorite-button-list-view"; 639 break; 640 case "quicklist-view": 641 favoriteButtonCss = "favorite-button-quicklist-view"; 642 break; 643 default: 644 favoriteButtonCss = "favorite-button-tiles-view"; 645 break; 646 } 647 648 <div id="@favoriteId" class=""> 649 @{ 650 string favorite = customerCenterLists.Any(l => l.Products.Any(p => p.ProductId == pvm.Id)) ? favoriteIcon : favoriteOutlineIcon; 651 } 652 <div> 653 @if (customerCenterLists.Count() > 0) 654 { 655 //Custom 656 Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites.FavoriteList favoriteLists = new Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites.FavoriteList(); 657 658 659 foreach (var list in customerCenterLists) 660 { 661 bool isInFavoriteList = list.Products.Any(p => p.ProductId == pvm.Id); 662 string addLink = "/Default.aspx?ID=" + modifyFavoriteListPage + "&feed=true&CCAddToMyLists=" + pvm.Id + "&CCAddToListVariantID=" + pvm.VariantId + "&CCAddToListLanguageID=" + pvm.LanguageId + "&CCAddToListID=" + list.ListId + "&CCListType=" + list.Type; 663 string removeLink = "/Default.aspx?ID=" + modifyFavoriteListPage + "&feed=true&CCRemoveFromMyLists=" + pvm.Id + "&CCRemoveFromListVariantID=" + pvm.VariantId + "&CCRemoveFromListLanguageID=" + pvm.LanguageId + "&ListID=" + list.ListId + "&CCListType=" + list.Type; 664 string favLinkType = isInFavoriteList ? removeLink : addLink; 665 string isInListIcon = isInFavoriteList ? favoriteIcon : favoriteOutlineIcon; 666 667 //Custom 668 <a href="@addLink" class="@favoriteButtonCss btn glyphicon glyphicon-star-empty js-favorite js-handle-favorite-add js-favorite-add-@favoriteId @(isInFavoriteList ? "hidden" : "")" data-fav-id="@(Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(favoriteId))" ><i class="@isInListIcon u-margin-right"></i></a> 669 <a href="@removeLink" class="@favoriteButtonCss btn glyphicon glyphicon-star js-favorite js-handle-favorite-remove js-favorite-remove-@favoriteId @(!isInFavoriteList ? "hidden" : "")" data-fav-id="@(Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(favoriteId))"><i class="@isInListIcon u-margin-right"></i></a> 670 } 671 } 672 else 673 { 674 string favLinkType = "/Default.aspx?ID=" + modifyFavoriteListPage + "&feed=true&DoNotShowVariantsAsSingleProducts=True&CCAddToMyLists=" + pvm.Id + "&CCAddToListVariantID=" + pvm.VariantId + "&CCAddToListLanguageID=" + pvm.LanguageId + "&CCListType=0&CCCreateNewList="; 675 <a href="@favLinkType" class="@favoriteButtonCss btn glyphicon glyphicon-star-empty"></a> 676 } 677 </div> 678 </div> 679 } 680 } 681 682 683 684 @{ 685 var useGoogleTagManager = !string.IsNullOrEmpty(Converter.ToString(Pageview.Area.Item["GoogleTagManager"])); 686 687 var isLoggedIn = Dynamicweb.Security.UserManagement.User.IsFrontendUserLoggedIn(); 688 689 var defaultImage = !string.IsNullOrWhiteSpace(Converter.ToString(Pageview.Area.Item["DefaultImage"])) ? Converter.ToString(Pageview.Area.Item["DefaultImage"]) : "/Files/images/default-image.png"; 690 691 var images = Model.ImagePatternImages; 692 string image = defaultImage; 693 694 if (images.Any()) 695 { 696 image = images.FirstOrDefault().Value; 697 } 698 699 var hasMultipleImages = images.Count > 1; 700 var hasThumbs = hasMultipleImages ? "has-bullets" : ""; @* originally has-thumbs *@ 701 702 var productService = Dynamicweb.Ecommerce.Services.Products; 703 string groupIdQueryParameter = string.IsNullOrEmpty(Dynamicweb.Context.Current.Request["GroupID"]) ? string.Empty : "&GroupID=" + Dynamicweb.Context.Current.Request["GroupID"]; 704 string currentPageLink = "/Default.aspx?ID=" + Pageview.Page.ID + groupIdQueryParameter; 705 var product = productService.GetProductById(Model.Id, Model.VariantId, true); 706 var productInfo = new ProductInformation(product, Dynamicweb.Security.UserManagement.User.GetCurrentFrontendUser()?.CustomerNumber); 707 var priceInformation = new PriceInformation(product, productInfo); 708 709 string productLink = currentPageLink + "&ProductID=" + product.Id; 710 711 DateTime availableFrom = DateTime.MinValue; 712 bool isDeliverable = Converter.ToDouble(priceInformation.Prices.PricePerColliUnit.Price) > 0 && DateTime.TryParseExact(Converter.ToString(CustomProductFieldHelpers.GetFieldValue("SpAvailableFrom", Model.ProductFields)), "dd-MM-yyyy", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out availableFrom) && Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime") != null && availableFrom <= CalenderHelper.ParseDateTime(Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime").Value); 713 714 int minQty = Converter.ToInt32(CustomProductFieldHelpers.GetFieldValue("MinimumPurchaseQuantityLimit", Model.ProductFields)); 715 if (minQty == 0) 716 { 717 switch (Converter.ToString(CustomProductFieldHelpers.GetFieldValue("MinimumPurchaseQuantity", Model.ProductFields)).ToLower().Trim()) 718 { 719 case "layer": 720 minQty = productInfo.ColliPerLayer; 721 break; 722 case "cc": 723 minQty = productInfo.ColliPerCc; 724 break; 725 default: 726 minQty = 1; 727 break; 728 } 729 } 730 731 string cssIDSelector = "js-" + Model.Id; 732 733 var priceRetailValue = productInfo.CustomerRetailPrice; 734 var priceRetail = new PriceCalculated(new PriceRaw(priceRetailValue, Dynamicweb.Ecommerce.Common.Context.Currency)); 735 var retailPriceValue = DisplayPricesInclVat() ? Converter.ToString(priceRetail.PriceWithVAT) : Converter.ToString(priceRetail.PriceWithoutVAT); 736 retailPriceValue = Converter.ToInt32(retailPriceValue) == 0 ? "" : FormatPrice(retailPriceValue); 737 738 var manufacturerName = Model.Manufacturer.Name; 739 var manufacturerId = Model.Manufacturer.Id; 740 var manufacturerWebsiteUrl = Model.Manufacturer.Web; 741 742 string specifier = "G"; 743 CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US"); 744 string productClass = "js-single-product-container"; 745 bool notActive = false; 746 if (!product.Active) 747 { 748 productClass += " in-active"; 749 notActive = true; 750 } 751 } 752 753 <div class="@productClass"> 754 <div id="productdetails" class="js-product js-single-product" data-min-quantity='@minQty' data-select-id="@cssIDSelector" data-has-multiple-images="@hasMultipleImages"> 755 <div class="page-header clearfix"> 756 <h1 class="page-header-h1 pull-left">@Model.Name</h1> 757 <a href="@currentPageLink" data-hide-on-async-load="true" class="js-close-product close-product-text pull-right"><i class="glyphicon glyphicon-chevron-left"></i> @Translate("Smartpage:ProductList.Back", "Back to product list")</a> 758 <a href="#" class="hide js-close-product close-product-text pull-right"><i class="glyphicon glyphicon-chevron-left"></i> @Translate("Smartpage:ProductList.Back", "Back to product list")</a> 759 </div> 760 <div class="border-bottom-box"> 761 <div class="col-sm-6 col-md-4 clearfix"> 762 @FavoriteHelper(Model, "product-detail") 763 <div class="list-group-item-img @hasThumbs"> 764 @renderImages("product-show") 765 @SingleAddedToCart(Model) 766 </div> 767 </div> 768 <div class="col-sm-12 col-md-4 clearfix product-wrapper"> 769 @Model.Name 770 @if (Converter.ToBoolean(CustomProductFieldHelpers.GetFieldValue("NewProduct", Model.ProductFields))) 771 { 772 <span class="label label-warning">@Translate("Smartpage:NewProduct", "NEW")</span> 773 } 774 @if (Converter.ToBoolean(CustomProductFieldHelpers.GetFieldValue("Bestseller", Model.ProductFields))) 775 { 776 <span class="label label-warning">@Translate("Smartpage:Bestseller", "BESTSELLER")</span> 777 } 778 @if (!string.IsNullOrEmpty(Converter.ToString(CustomProductFieldHelpers.GetFieldValue("NavCompanyCode", Model.ProductFields)))) 779 { 780 var flagImgPath = "/Admin/Images/Flags/Small/flag_" + Converter.ToString(CustomProductFieldHelpers.GetFieldValue("NavCompanyCode", Model.ProductFields)) + ".png"; 781 <img src='@flagImgPath' alt='@Converter.ToString(CustomProductFieldHelpers.GetFieldValue("NavCompanyCode", Model.ProductFields))' title='@Converter.ToString(CustomProductFieldHelpers.GetFieldValue("NavCompanyCode", Model.ProductFields))' /> 782 } 783 </h2> 784 <div class="product-description"> 785 <div class="product-description"> 786 @SingleStockStatus(Model) 787 @Model.ShortDescription 788 </div> 789 <div class="product-unit"> 790 Ø @FormatDiameter(Converter.ToString(CustomProductFieldHelpers.GetFieldValue("ProductPotSize", Model.ProductFields)) + " cm") @FormatDiameter("H: " + product.Height + " cm") 791 </div> 792 @RenderManufacturer(manufacturerId, manufacturerName, manufacturerWebsiteUrl) 793 794 @if (Converter.ToInt32(CustomProductFieldHelpers.GetFieldValue("LeadDays", Model.ProductFields)) > 0) 795 { 796 <div class="row bottom"> 797 <div class="col-sm-12 col-md-12 col-lg-9 product-lead-days "> 798 <span class="label label-warning">@Translate("Smartpage:Ecom.LeadDaysMessage", "Lead days") @Converter.ToInt32(CustomProductFieldHelpers.GetFieldValue("LeadDays", Model.ProductFields))</span> 799 </div> 800 </div> 801 } 802 803 @if (isLoggedIn) 804 { 805 var cssIsAvailable = isDeliverable ? "available" : "not-available"; 806 <div class="row"> 807 <div class='product-price @cssIsAvailable col-sm-12'> 808 <div class="product-colors"> 809 @{ 810 var colors = CustomProductFieldHelpers.GetFieldValue("Color", Model.ProductFields) as List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>; 811 812 foreach (var c in colors) 813 { 814 if (c.Value != "XXXXXX") 815 { 816 var backgroundColor = "#" + c.Value; 817 <span class="product-color" style="background-color:@backgroundColor" title='@c.Name'> 818 819 </span> 820 } 821 else 822 { 823 <span class="product-color" title='@c.Name'> 824 <img src="/Files/images/multi-color.png" class="img-responsive" title='@c.Name' /> 825 </span> 826 } 827 } 828 } 829 </div> 830 <table class="table"> 831 <thead> 832 <tr> 833 <td> </td> 834 <th> 835 <div class="pictogram"> 836 <div class="pictogram-box"></div> 837 </div> 838 </th> 839 <th> 840 <div class="pictogram"> 841 <div class="pictogram-layer"></div> 842 </div> 843 </th> 844 <th> 845 <div class="pictogram"> 846 <div class="pictogram-container"></div> 847 </div> 848 </th> 849 </tr> 850 </thead> 851 <tbody> 852 <tr> 853 <td> 854 @Translate("Pcs", "Stk") 855 </td> 856 <td> 857 1 × 858 @productInfo.ColliSize 859 </td> 860 <td> 861 <span class="js-colli-per-layer">@productInfo.ColliPerLayer</span> 862 × @productInfo.ColliSize 863 </td> 864 <td> 865 <span class="js-colli-per-cc">@productInfo.ColliPerCc</span> 866 × @productInfo.ColliSize 867 </td> 868 </tr> 869 @if (!DisablePrices()) 870 { 871 <tr> 872 <td> 873 @Translate("price", "Pris") 874 </td> 875 <td class="js-product-field-price js-product-field-price-colli"> 876 @if (DisplayPricesInclVat()) 877 { 878 if (Converter.ToDouble(priceInformation.Prices.PricePerColliUnit.PriceWithVAT) > 0) 879 { 880 @:@priceInformation.Prices.PricePerColliUnit.PriceWithVAT.ToString("0.00") 881 } 882 883 } 884 else 885 { 886 if (Converter.ToDouble(priceInformation.Prices.PricePerColliUnit.PriceWithoutVAT) > 0) 887 { 888 @:@priceInformation.Prices.PricePerColliUnit.PriceWithoutVAT.ToString("0.00") 889 } 890 } 891 </td> 892 <td class="js-product-field-price js-product-field-price-layer"> 893 @if (DisplayPricesInclVat()) 894 { 895 if (Converter.ToDouble(priceInformation.Prices.PricePerLayerUnit.PriceWithVAT) > 0) 896 { 897 @:@priceInformation.Prices.PricePerLayerUnit.PriceWithVAT.ToString("0.00") 898 } 899 } 900 else 901 { 902 if (Converter.ToDouble(priceInformation.Prices.PricePerLayerUnit.PriceWithoutVAT) > 0) 903 { 904 @:@priceInformation.Prices.PricePerLayerUnit.PriceWithoutVAT.ToString("0.00") 905 } 906 } 907 </td> 908 <td class="js-product-field-price js-product-field-price-cc"> 909 @if (DisplayPricesInclVat()) 910 { 911 if (Converter.ToDouble(priceInformation.Prices.PricePerCcUnit.PriceWithVAT) > 0) 912 { 913 @:@priceInformation.Prices.PricePerCcUnit.PriceWithVAT.ToString("0.00") 914 } 915 } 916 else 917 { 918 if (Converter.ToDouble(priceInformation.Prices.PricePerCcUnit.PriceWithoutVAT) > 0) 919 { 920 @:@priceInformation.Prices.PricePerCcUnit.PriceWithoutVAT.ToString("0.00") 921 } 922 } 923 </td> 924 </tr> 925 } 926 </tbody> 927 </table> 928 </div> 929 </div> 930 } 931 </div> 932 </div> 933 <div class="row"> 934 <div class="col-sm-offset-6 col-sm-6 col-md-offset-0 col-md-4 clearfix product-wrapper"> 935 936 @if (isLoggedIn && priceInformation.Prices.PricePerColliUnit.Price > 0) 937 { 938 <form name='@Model.Id' method="get" action='/Default.aspx?ID=@Pageview.Page.ID' class="js-product-informations js-basket-add js-product-form-container product-informations-details" autocomplete="false" data-submit-url='@Pageview.Area.Item["JsonCart"]'> 939 <input type="hidden" name="Spleadday-accepted" class="js-leadday-accepted" value="false" /> 940 <input type="hidden" name="ProductURL" id="ProductURL" value=""> 941 <input type="hidden" name="CartCmd" id="CartCmd" value="add"> 942 <input type="hidden" class="js-product-id" name="ProductID" id="ProductID" value="@Model.Id"> 943 <input type="hidden" name="VariantID" id="VariantID" value="@Model.VariantId"> 944 <input type="hidden" name="UnitID" id="UnitID" value="@product.DefaultUnitId"> 945 @if (Converter.ToInt32(CustomProductFieldHelpers.GetFieldValue("LeadDays", Model.ProductFields)) > 0) 946 { 947 <input class="js-leadday-amount" type="hidden" value="@Converter.ToInt32(CustomProductFieldHelpers.GetFieldValue("LeadDays", Model.ProductFields))" name="SpLeadDaysOnProduct_@Model.Id" /> 948 <input class="js-available-from-date" type="hidden" value="@(AvailableDeliveryDay(Converter.ToInt32(CustomProductFieldHelpers.GetFieldValue("LeadDays", Model.ProductFields))))" name="SpAvailableFromDate_@Model.Id" /> 949 } 950 <div class="product-input"> 951 952 @if (!String.IsNullOrEmpty(productInfo.CustomerItemNumber) && false) 953 { 954 <div class="col-sm-9 col-sm-offset-3 col-lg-offset-3 col-lg-9 text-right product-editable-area product-price-container-single-view"> 955 <i class="text-muted"> 956 <span class="pull-left">@Translate("Deres_varenummer", "Your Item No.")</span> 957 <span class="pull-right">@productInfo.CustomerItemNumber</span> 958 </i> 959 </div> 960 } 961 @{ 962 string customerSpecificRemark = productInfo.CustomerSpecificRemark; 963 964 if (!string.IsNullOrWhiteSpace(customerSpecificRemark)) 965 { 966 <div class="col-sm-9 col-sm-offset-3 col-lg-offset-3 col-lg-9 text-right product-editable-area"> 967 <i class="text-muted"> 968 <span class="pull-left">@Translate("Deres_bemaerkning", "Your Comment")</span> 969 <span class="pull-right">@customerSpecificRemark</span> 970 </i> 971 </div> 972 } 973 } 974 975 @if (EnableDisplayOfGrossMargin()) 976 { 977 double customerSalesPrice = DisplayPricesInclVat() ? priceInformation.Prices.PricePerColliUnit.PriceWithVAT : priceInformation.Prices.PricePerColliUnit.PriceWithoutVAT; 978 979 <div class="col-sm-9 col-sm-offset-3 col-lg-offset-3 col-lg-9 text-right product-retail-price product-editable-area product-price-container-single-view"> 980 <i class="js-product-field-gross-margin text-muted"> 981 <span class="pull-left">@Translate("Smartpage:eCom:CustomerSpecificInfo.GrossMargin", "Gross margin")</span> 982 <span class="pull-right js-gross-margin-value"> 983 @if (productInfo.CustomerRetailPrice > 0) 984 { 985 @GetGrossMargin(productInfo.CustomerRetailPrice, customerSalesPrice); 986 } 987 else 988 { 989 @Translate("Smartpage:ecom:CustomerSpecificInfo.GrossMargin.NA", "N/A") 990 } 991 </span> 992 </i> 993 994 </div> 995 } 996 997 @if (EnableCustomerRetailPrice()) 998 { 999 <div class="col-sm-9 col-sm-offset-3 col-lg-offset-3 col-lg-9 text-right product-retail-price product-editable-area product-price-container-single-view"> 1000 @if (EnableEditableRetailPrice() && isDeliverable) 1001 { 1002 <div class="product-selectable-edit pull-right"> 1003 <i class="glyphicon glyphicon-edit js-product-fields-edit product-fields-edit" data-source="#js-retail-price"></i> 1004 </div> 1005 } 1006 <div class="js-product-field-retail-price"> 1007 <span class="pull-left">@Translate("Smartpage:eCom:CustomerSpecificInfo.RetailPrice", "Retail price")</span> 1008 <span class="pull-right">@retailPriceValue</span> 1009 </div> 1010 </div> 1011 } 1012 @if (EnableCustomerItemNumber()) 1013 { 1014 <div class="col-sm-offset-3 col-sm-9 text-right product-item-number product-editable-area product-price-container-single-view"> 1015 @if (EnableEditableItemNumber() && isDeliverable) 1016 { 1017 <div class="product-selectable-edit pull-right"> 1018 <i class="glyphicon glyphicon-edit js-product-fields-edit product-fields-edit" data-source="#js-item-number"></i> 1019 </div> 1020 } 1021 <div class="js-product-field-item-number text-left"> 1022 <span class="pull-left">@Translate("Smartpage:eCom:CustomerSpecificInfo.ItemNumber", "Item no.")</span> 1023 <span class="pull-right">@productInfo.CustomerItemNumber</span> 1024 </div> 1025 </div> 1026 } 1027 @{ var cssPaddingTop = isDeliverable ? "product-editable-container" : ""; } 1028 1029 <div class="col-sm-9 col-sm-offset-3 @cssPaddingTop product-editable-area "> 1030 @if (EnableEditableBarcode() && isDeliverable) 1031 { 1032 <span class="product-selectable-edit pull-right"> 1033 <i class="glyphicon glyphicon-edit pull-right js-product-fields-edit product-fields-edit" data-source="#js-ean-number"></i> 1034 </span> 1035 } 1036 @if (EnableCustomerBarcode() && !String.IsNullOrEmpty(productInfo.EAN)) 1037 { 1038 <div class="js-product-field-ean"> 1039 <span class="pull-left">@Translate("Deres_EAN_nummer", "EAN")</span> 1040 <span class="pull-right">@productInfo.EAN</span> 1041 </div> 1042 } 1043 <div class="clearfix"></div> 1044 </div> 1045 @if (isDeliverable) 1046 { 1047 bool isServiceProduct = product.Type == Dynamicweb.Ecommerce.Products.ProductType.Service; 1048 <div class="col-sm-3 js-quantity-tooltip" data-placement="top" data-toggle="popover" data-trigger="manual"> 1049 @renderToolTip() 1050 <div class="form-group"> 1051 <input type="number" min="0" name='Quantity' data-is-service="@isServiceProduct" data-stock-status='@Model.StockLevel' class="form-control js-quantity" placeholder="0" /> 1052 </div> 1053 </div> 1054 <div class="col-sm-9"> 1055 <div class="form-group"> 1056 @foreach (var o in product.OrderLineFields) 1057 { 1058 var inputName = "EcomOrderLineFieldInput_" + o.Name; 1059 string placeholderText = o.Name; 1060 1061 switch (o.SystemName) 1062 { 1063 case "OrderLineComment": 1064 if (EnableComments()) 1065 { 1066 placeholderText = Translate("LineComment", "Comment"); 1067 <input type="text" class="form-control" name='@inputName' maxlength="80" placeholder='@placeholderText' /> 1068 } 1069 break; 1070 case "OrderLineColliSize": 1071 <input type="hidden" name="@inputName" value='@productInfo.ColliSize' /> 1072 break; 1073 case "OrderLineColliPerLayer": 1074 <input type="hidden" name="@inputName" value='@productInfo.ColliPerLayer' /> 1075 break; 1076 case "OrderLineColliPerCC": 1077 <input type="hidden" name="@inputName" value='@productInfo.ColliPerLayer' /> 1078 break; 1079 case "OrderLineEAN": 1080 placeholderText = Translate("Deres_EAN_nummer-short", "EAN"); 1081 <div class="hidden col-sm-12"> 1082 <input type="text" class="form-control js-product-field-replace text-right" id="js-ean-number" data-replace-target=".js-product-field-ean" name="@inputName" value='@productInfo.EAN.Trim()' placeholder="@placeholderText" /> 1083 </div> 1084 break; 1085 case "OrderLineRetailPrice": 1086 placeholderText = Translate("Smartpage:eCom:CustomerSpecificInfo.RetailPrice", "Add retail price"); 1087 <div class="hidden"> 1088 <input type="text" id="js-retail-price" class="form-control js-product-field-replace js-retail-price-input text-right" data-replace-target=".js-product-field-retail-price" name="@inputName" value='@retailPriceValue' placeholder="@placeholderText" /> 1089 </div> 1090 break; 1091 case "OrderLineItemNumber": 1092 placeholderText = Translate("Smartpage:eCom:CustomerSpecificInfo.ItemNumber", "Item no."); 1093 <div class="hidden"> 1094 <input type="text" id="js-item-number" class="form-control js-product-field-replace text-right" data-replace-target=".js-product-field-item-number" name="@inputName" value='@productInfo.CustomerItemNumber.Trim()' placeholder="@placeholderText" /> 1095 </div> 1096 break; 1097 } 1098 } 1099 </div> 1100 </div> 1101 <div class="clearfix"></div> 1102 <div class="col-sm-9 col-sm-offset-3"> 1103 <button type="submit" class="pull-right btn btn-primary js-gtm-addtocart" data-name="@HttpUtility.HtmlAttributeEncode(Model.Name)" data-id="@HttpUtility.HtmlAttributeEncode(Model.Id)" data-price="@HttpUtility.HtmlAttributeEncode((DisplayPricesInclVat() ? Model.Price.PriceWithVat.ToString(specifier, culture) : Model.Price.PriceWithoutVat.ToString(specifier, culture)))">@Translate("Smartpage:eCom.AddToCart", "Læg i kurven")</button> 1104 </div> 1105 } 1106 1107 @* If product has lead day *@ 1108 @if (Converter.ToInt32(CustomProductFieldHelpers.GetFieldValue("LeadDays", Model.ProductFields)) > 0 && Converter.ToString(CustomProductFieldHelpers.GetFieldValue("SpAvailableFrom", Model.ProductFields)) == string.Empty) 1109 { 1110 <div class="col-sm-offset-3 col-sm-9 product-not-available product-editable-area"> 1111 <p class="pull-left">@Translate("Smartpage:Ecom.LeadDaysWarning", "Available on") <span class="label label-warning pull-right not-deliverable"> @(AvailableDeliveryDay(Converter.ToInt32(CustomProductFieldHelpers.GetFieldValue("LeadDays", Model.ProductFields))))</span></p> 1112 </div> 1113 } 1114 @* If 'Available from' is in the future *@ 1115 else if (Converter.ToString(CustomProductFieldHelpers.GetFieldValue("SpAvailableFrom", Model.ProductFields)) != string.Empty && Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime") != null && availableFrom > CalenderHelper.ParseDateTime(Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime").Value)) 1116 { 1117 <div class="col-sm-offset-3 col-sm-9 product-not-available product-editable-area"> 1118 <p class="pull-left">@Translate("Smartpage:Ecom.AvailableFromWarning", "Available from") <span class="label label-warning pull-right not-deliverable"> @(CustomProductFieldHelpers.GetFieldValue("SpAvailableFrom", Model.ProductFields))</span></p> 1119 </div> 1120 } 1121 @* If there is no prices *@ 1122 else if (!priceInformation.ArePricesAvailable(product.Number, Dynamicweb.Security.UserManagement.User.GetCurrentFrontendUser()?.CustomerNumber)) 1123 { 1124 <div class="col-sm-offset-3 col-sm-9 product-not-available product-editable-area"> 1125 <p><span class="label label-warning pull-right not-deliverable"> @(Translate("Smartpage:Ecom.NoPricesOnProductWarning", "Prices are being generated"))</span></p> 1126 </div> 1127 } 1128 @* If there is no valid prices *@ 1129 else if (Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime") != null && Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime").Value != null && priceInformation.ArePricesValidInTheFuture(product.Number, CalenderHelper.ParseDateTime(Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime").Value), Dynamicweb.Security.UserManagement.User.GetCurrentFrontendUser()?.CustomerNumber)) 1130 { 1131 1132 1133 <div class="col-sm-offset-3 col-sm-9 product-not-available product-editable-area"> 1134 <p class="pull-left">@Translate("Smartpage:Ecom.PricesValidFrom", "Prices available on") <span class="label label-warning pull-right not-deliverable"> @(priceInformation.GetValidFromDate(product.Number, CalenderHelper.ParseDateTime(Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime").Value), Dynamicweb.Security.UserManagement.User.GetCurrentFrontendUser()?.CustomerNumber))</span></p> 1135 </div> 1136 } 1137 @* If there is no valid prices *@ 1138 else if (Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime") != null && Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime").Value != null && priceInformation.ArePricesExpired(product.Number, CalenderHelper.ParseDateTime(Dynamicweb.Ecommerce.Common.Context.Cart.OrderFieldValues.GetOrderFieldValue("DeadlineTime").Value), Dynamicweb.Security.UserManagement.User.GetCurrentFrontendUser()?.CustomerNumber)) 1139 { 1140 <div class="col-sm-offset-3 col-sm-9 product-not-available product-editable-area"> 1141 <p><span class="label label-warning pull-right not-deliverable"> @(Translate("Smartpage:Ecom.NoPricesFoundOnDeliveryDate", "No prices found on Delivery Date"))</span></p> 1142 </div> 1143 } 1144 1145 </div> 1146 <!-- @CustomProductFieldHelpers.GetFieldValue("SpAvailableFrom", Model.ProductFields) <br/><br/> --> 1147 1148 1149 </form> 1150 } 1151 @if(!String.IsNullOrEmpty(CustomProductFieldHelpers.GetFieldValue("ProductColor", Model.ProductFields)+"")) 1152 { 1153 <p>@(Translate("Color", "Color")): @CustomProductFieldHelpers.GetFieldValue("ProductColor", Model.ProductFields) </p> 1154 } 1155 @if(!String.IsNullOrEmpty(CustomProductFieldHelpers.GetFieldValue("ProductLighting", Model.ProductFields)+"")) 1156 { 1157 <p>@(Translate("Lighting", "Lighting")): @CustomProductFieldHelpers.GetFieldValue("ProductLighting", Model.ProductFields) </p> 1158 } 1159 @if(!String.IsNullOrEmpty(CustomProductFieldHelpers.GetFieldValue("ProductTheme", Model.ProductFields)+"")) 1160 { 1161 <p>@(Translate("Theme", "Theme")): @CustomProductFieldHelpers.GetFieldValue("ProductTheme", Model.ProductFields) </p> 1162 } 1163 @if(!String.IsNullOrEmpty(CustomProductFieldHelpers.GetFieldValue("ProductStage", Model.ProductFields)+"")) 1164 { 1165 <p>@(Translate("Stage", "Stage")): @CustomProductFieldHelpers.GetFieldValue("ProductStage", Model.ProductFields) </p> 1166 } 1167 @if(!String.IsNullOrEmpty(CustomProductFieldHelpers.GetFieldValue("ProductTypeCode", Model.ProductFields)+"")) 1168 { 1169 <p>@(Translate("TypeCode", "TypeCode")): @CustomProductFieldHelpers.GetFieldValue("ProductTypeCode", Model.ProductFields) </p> 1170 } 1171 1172 @{ 1173 var detailsLoop = product.Details; 1174 if (detailsLoop.Any()) 1175 { 1176 <div class="product-files"> 1177 <div class="row"> 1178 @foreach (var i in detailsLoop) 1179 { 1180 string fileName = string.Empty; 1181 var fileInfo = new System.IO.FileInfo("Files" + i.Value); 1182 if (fileInfo != null) 1183 { 1184 fileName = fileInfo.Name; 1185 } 1186 1187 string link = i.Value; 1188 if (!string.IsNullOrWhiteSpace(link)) 1189 { 1190 <div class="col-sm-12"> 1191 <div class="row"> 1192 <a href='@link' target="_blank"> 1193 <img class="pdf-img" src="/Files/Templates/Designs/Gasa/Assets/images/pdf_icon.png" /> 1194 </a> 1195 <a href='Files/@link' target="_blank"> 1196 @fileName 1197 </a> 1198 </div> 1199 </div> 1200 } 1201 } 1202 </div> 1203 </div> 1204 } 1205 } 1206 </div> 1207 </div> 1208 </div> 1209 <div class="clearfix visible-sm"></div> 1210 1211 <div class="clearfix"></div> 1212 </div> 1213 </div> 1214 @PricesWithVATStatus("bottom") 1215 1216 @{ 1217 string spRelationFamilyId = Converter.ToString(CustomProductFieldHelpers.GetFieldValue("SpRelationFamilyId", Model.ProductFields)); 1218 } 1219 1220 @if (GetPageIdByNavigationTag("SpRelatedProducts") != 0 && !string.IsNullOrEmpty(spRelationFamilyId)) 1221 { 1222 <div class="col-sm-12"> 1223 <div class="row related-products-wrap product-page js-load-related-products" data-url="/Default.aspx?ID=@GetPageIdByNavigationTag("SpRelatedProducts")&SpRelationFamilyId=@spRelationFamilyId&DoNotShow=@Model.Number&Checkout=False"></div> 1224 </div> 1225 } 1226 1227 <div id="js-modal-full" class="modal fade" tabindex="-1" role="dialog"> 1228 <div class="modal-dialog"> 1229 <div class="modal-content"> 1230 <div class="modal-header"> 1231 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> 1232 <h4 class="modal-title">@Model.Name</h4> 1233 </div> 1234 <div class="modal-body"> 1235 <div class="row"> 1236 <div class="col-sm-12"> 1237 @renderImages("fullscreen-show") 1238 </div> 1239 </div> 1240 </div> 1241 </div><!-- /.modal-content --> 1242 </div><!-- /.modal-dialog --> 1243 </div><!-- /.modal --> 1244 </div> 1245 1246 @helper renderImages(string container) 1247 { 1248 var defaultImage = !string.IsNullOrWhiteSpace(Converter.ToString(Pageview.Area.Item["DefaultImage"])) ? Converter.ToString(Pageview.Area.Item["DefaultImage"]) : "/Files/images/default-image.png"; 1249 var hasMultipleImages = Model.ImagePatternImages.Count > 1; 1250 1251 var images = Model.ImagePatternImages; 1252 string imageUrl = defaultImage; 1253 1254 bool isCdnActive = Converter.ToBoolean(Pageview.Area.Item["CDNActivate"]); 1255 1256 if (images.Any()) 1257 { 1258 imageUrl = images.FirstOrDefault().Value; 1259 } 1260 1261 string cdnHost = ""; 1262 if (isCdnActive) 1263 { 1264 cdnHost = Converter.ToString(Pageview.Area.Item["CDNUrl"]); 1265 } 1266 1267 <div class="ms-showcase2-template ms-showcase2-vertical"> 1268 <div class="master-slider ms-skin-light-5" id="js-@container"> 1269 @{ 1270 var imagesLoop = Model.ImagePatternImages; 1271 } 1272 1273 @if (imagesLoop.Any()) 1274 { 1275 int count = 0; 1276 foreach (var image in imagesLoop) 1277 { 1278 count++; 1279 string loopUrl = image.Value; 1280 string currentImageUrl = cdnHost + "/Admin/Public/getimage.ashx?Image=" + loopUrl + "&Resolution=75&Compression=70&Width=720&Width=480&Crop=5&AlternativeImage=" + defaultImage; 1281 string fallBackImage = $"/Admin/Public/getimage.ashx?Image={loopUrl}&Resolution=75&Compression=70&Width=720&Width=480&Crop=5&AlternativeImage={defaultImage}"; 1282 string currentThumbUrl = cdnHost + "/Admin/Public/getimage.ashx?Image=" + loopUrl + "&Compression=90&Width=63&&Height=42&Crop=5"; 1283 string isActiveClass = count == 1 ? "active" : ""; 1284 <div class="ms-slide js-slide-elm" data-slide-no='@count'> 1285 <img src="@currentImageUrl" data-src="@currentImageUrl" data-fallback-image-url="@fallBackImage" alt="@Model.Name @count" class="b-lazy" /> 1286 @if (container == "product-show") 1287 { 1288 <a href="#" class="ms-layer ms-btn fullscreen-btn js-show-fullscreen" data-offset-x="10" data-offset-y="15" data-type="button" data-duration="500"><i class="glyphicon glyphicon-fullscreen"></i></a> 1289 } 1290 1291 </div> 1292 } 1293 } 1294 else 1295 { 1296 string currentImageUrl = cdnHost + "/Admin/Public/getimage.ashx?Image=" + imageUrl + "&Resolution=75&Compression=70&Width=720&Width=480&Crop=5&AlternativeImage=" + defaultImage; 1297 <div class="ms-slide js-slide-elm" data-slide-no='1'> 1298 <img src="@currentImageUrl" data-src="@currentImageUrl" alt="@Model.Name" /> 1299 @if (container == "product-show") 1300 { 1301 <a href="#" class="ms-layer ms-btn fullscreen-btn js-show-fullscreen" data-offset-x="10" data-offset-y="15" data-type="button" data-duration="500"><i class="glyphicon glyphicon-fullscreen"></i></a> 1302 } 1303 1304 </div> 1305 } 1306 </div> 1307 </div> 1308 } 1309 1310 @SnippetStart("JavaScript") 1311 <script type="text/javascript"> 1312 1313 $(document).ready(function () { 1314 1315 var hasMultipleImages = $(".js-product").data("has-multiple-images"); 1316 1317 if (typeof (hasMultipleImages) == 'string') { 1318 hasMultipleImages = hasMultipleImages.toLowerCase(); 1319 } 1320 1321 $(".js-show-fullscreen").on("click", function (e) { 1322 e.preventDefault(); 1323 fullscreenSlider.currentSlideNo = Number($(this).closest(".js-slide-elm").attr("data-slide-no")) - 1; 1324 setTimeout(function () { 1325 $("#js-modal-full").modal("show"); 1326 }, 300); 1327 }); 1328 var fullscreenSlider = {}; 1329 $("#js-modal-full").on("shown.bs.modal", function () { 1330 var slideOptions = { 1331 view: "flow", 1332 layout: "fillwidth", 1333 autoHeight: true, 1334 width: 720, 1335 height: 480 1336 }; 1337 if (typeof fullscreenSlider.slider == "undefined") { 1338 fullscreenSlider.slider = new MasterSlider(); 1339 if (hasMultipleImages == "true") { 1340 fullscreenSlider.slider.control('arrows', { autohide: false }); 1341 //fullscreenSlider.slider.control('bullets', { autohide: false, dir: "h", align: "bottom", margin: 10 }); 1342 } 1343 fullscreenSlider.slider.setup('js-fullscreen-show', slideOptions); 1344 if (!isNaN(fullscreenSlider.currentSlideNo)) { 1345 fullscreenSlider.slider.api.gotoSlide(fullscreenSlider.currentSlideNo); // moves to 4th slide. 1346 } 1347 } 1348 else { 1349 if (!isNaN(fullscreenSlider.currentSlideNo)) { 1350 fullscreenSlider.slider.api.gotoSlide(fullscreenSlider.currentSlideNo); // moves to 4th slide. 1351 } 1352 } 1353 }); 1354 1355 1356 var slider = new MasterSlider(); 1357 if (hasMultipleImages == "true") { 1358 slider.control('arrows', { autohide: false }); 1359 //slider.control('bullets', { autohide: false, dir: "h", align: "bottom", margin: 10 }); 1360 } 1361 slider.setup('js-product-show', { 1362 view: "flow", 1363 layout: "fillwidth", 1364 autoHeight: true, 1365 width: 720, 1366 height: 480 1367 }); 1368 $(".js-variant").each(function () { 1369 updateVariants($(this)); 1370 }); 1371 1372 $(".js-variant").change(function () { 1373 updateVariants($(this)); 1374 1375 var productContainer = $(this).closest(".js-product-informations"); 1376 1377 var product = { 1378 productId: $("input[name=ProductID]", productContainer).val(), 1379 variantId: $("input[name=VariantID]", productContainer).val(), 1380 pageId: _pageId 1381 }; 1382 1383 $.ajax({ 1384 type: 'POST', 1385 url: '/files/services/PriceService.asmx/GetPrice', 1386 data: JSON.stringify(product), 1387 contentType: "application/json; charset=utf-8", 1388 dataType: 'json', 1389 processdata: true, 1390 beforeSend: function () { startLoading(); }, 1391 complete: function (jqXHR, status) { endLoading(); }, 1392 success: function (result) { 1393 1394 if (result.d) { 1395 $(".js-product-price", productContainer).text(result.d); 1396 } else { 1397 //$('#unsubscribe').modal('hide'); 1398 //$('#unsubscribe-error').modal('show'); 1399 } 1400 } 1401 }); 1402 1403 1404 }); 1405 }); 1406 1407 function updateVariants(chosenElm) { 1408 var chosenValue = chosenElm.val(); 1409 //alert(chosenElm.val()); 1410 var containerBlock = $(chosenElm).closest(".js-product-informations"); 1411 var variantCombinations = []; 1412 1413 $("input[name=js-variant-combination]", containerBlock).each(function (index, elm) { 1414 variantCombinations.push($(elm).val()); 1415 }); 1416 1417 var numVariantLevels = $(".js-variant", containerBlock).length; 1418 $(".js-variant", containerBlock).each(function (index, elm) { 1419 if ($(elm).attr("id") != chosenElm.attr("id")) { 1420 var isDisabledSelected = false; 1421 var selectValue = $(elm).val(); 1422 $("option", elm).each(function () { 1423 var found = false; 1424 if (jQuery.inArray(this.value + variantDelimiter + chosenValue, variantCombinations) > -1) { 1425 found = true; 1426 if (this.value == selectValue) { 1427 $(containerBlock).find("input[name=VariantID]").val(this.value + variantDelimiter + chosenValue); 1428 } 1429 } else if (jQuery.inArray(chosenValue + variantDelimiter + this.value, variantCombinations) > -1) { 1430 found = true; 1431 if (this.value == selectValue) { 1432 $(containerBlock).find("input[name=VariantID]").val(chosenValue + variantDelimiter + this.value); 1433 } 1434 } 1435 1436 if (!found && selectValue === this.value) { 1437 isDisabledSelected = true; 1438 //alert("option[value=" + this.value + "]"); 1439 } 1440 $("option[value='" + this.value + "']", elm).attr("disabled", !found); 1441 }); 1442 1443 if (isDisabledSelected) { 1444 // Setting first option to be selected 1445 $(elm).val($("option:not(:disabled)", elm).eq(0).val()); 1446 } 1447 } 1448 else { 1449 if (numVariantLevels == 1) { 1450 $(containerBlock).find("input[name=VariantID]").val(chosenElm.val()); 1451 } 1452 } 1453 }); 1454 } 1455 </script> 1456 1457 @if (useGoogleTagManager) 1458 { 1459 <script> 1460 dataLayer.push({ 1461 "event": "productDetails", 1462 "ecommerce": { 1463 "detail": { 1464 "actionField": {}, 1465 "products": [{ 1466 "name": "@HttpUtility.JavaScriptStringEncode(Model.Name)", 1467 "id": "@HttpUtility.JavaScriptStringEncode(Model.Id)", 1468 "price": "@HttpUtility.JavaScriptStringEncode((DisplayPricesInclVat() ? Model.Price.PriceWithVat.ToString(specifier, culture) : Model.Price.PriceWithoutVat.ToString(specifier, culture)))", 1469 "currency": "@HttpUtility.JavaScriptStringEncode(Dynamicweb.Ecommerce.Common.Context.Currency.Code)", 1470 "brand": "@HttpUtility.JavaScriptStringEncode(manufacturerName)" 1471 }] 1472 } 1473 } 1474 }); 1475 </script> 1476 } 1477 @SnippetEnd("JavaScript") 1478 1479 @* helpers *@ 1480 1481

English
français
Deutsch
dansk
svenska
italiano
suomi