Error executing template "Designs/ClientBase_generated/Paragraph/ProductDetailWidgetRelatedProducts.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass6_0.<GetRelatedGroups>b__1(IGrouping`2 group)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at System.Lazy`1.CreateValue()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Lazy`1.get_Value()
at CompiledRazorTemplates.Dynamic.RazorEngine_d4de60c65a7341b2a32b8c10f12d43b5.Execute() in D:\dynamicweb.net\Solutions\Bluedesk\koksgroup.cloud.dynamicweb-cms.com\files\Templates\Designs\ClientBase_generated\Paragraph\ProductDetailWidgetRelatedProducts.cshtml:line 25
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 Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel>
2 @using Dynamicweb.Ecommerce.Prices;
3 @using Dynamicweb.Ecommerce.ProductCatalog;
4 @using Bluedesk.DynamicWeb.ItemTypes.BaseSolution;
5 @using Bluedesk.DynamicWeb.ItemTypes.Settings.Configuration;
6
7 @{
8 string paragraphID = Pageview.CurrentParagraph.ID.ToString();
9 ProductDetailWidgetRelatedProducts _data = Dynamicweb.Services.Items.GetItem("ProductDetailWidgetRelatedProducts", Model.ItemId).ToCodeFirstItem<ProductDetailWidgetRelatedProducts>() ?? new ProductDetailWidgetRelatedProducts();
10
11 ProductViewModel product = new ProductViewModel();
12 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
13 {
14 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
15 }
16
17 var selectedGroups = _data.SelectedGroups;
18
19 string ElementID = !string.IsNullOrWhiteSpace(_data.CustomID) ? _data.CustomID : paragraphID;
20
21 }
22
23 <section id="@ElementID" class="pdp-paragraph pdp-related-products-widget @_data.CssClass">
24 @foreach(var selectedGroup in selectedGroups) {
25 RelatedGroupViewModel relatedGroup = product?.RelatedGroups?.FirstOrDefault(obj => obj.Id == selectedGroup.RelatedGroupID);
26 if (relatedGroup != null)
27 {
28 IEnumerable<ProductViewModel> relatedProducts = relatedGroup.GetRelatedProducts();
29 string groupName = Translate("ProductRelatedGroup." + relatedGroup.Name.Replace(" ", ""), relatedGroup.Name);
30
31 string CustomID = !string.IsNullOrWhiteSpace(_data.CustomID) ? $"id='{_data.CustomID}'" : "";
32
33 if (relatedProducts.Any())
34 {
35 var index = 1;
36 <section class="products-module__container @selectedGroup.CssClass" @CustomID>
37 <div class="container">
38
39 <header class="products-module__header">
40 <h2 class="products-module__title">@groupName</h2>
41 </header>
42
43 <ul class="products-module__slider">
44 @foreach (var p in relatedProducts)
45 {
46 @renderProductBlock(p, relatedGroup.Name, relatedGroup.Id, index);
47 index++;
48 }
49 </ul>
50 </div>
51 </section>
52
53 @renderProductListEnhancedEcom(relatedGroup.Id, relatedGroup.Name, relatedProducts)
54 }
55 }
56 }
57 </section>
58
59 @helper renderProductBlock(Dynamicweb.Ecommerce.ProductCatalog.ProductViewModel product, string listId, string listName, int index)
60 {
61 var master_configuration = Dynamicweb.Services.Pages.GetPageByNavigationTag(Pageview.AreaID, "MasterConfiguration");
62 MasterConfig mc = master_configuration.Item.ToCodeFirstItem<MasterConfig>();
63 EcomConfig EcommerceConfiguration = mc.EcomConfiguration;
64
65 string productName = product.Name;
66 string productImage = product.DefaultImage?.Value ?? "";
67
68 if (string.IsNullOrWhiteSpace(productImage))
69 {
70 var prodService = new Dynamicweb.Ecommerce.Products.ProductService();
71 var p = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, product.VariantId, Pageview.Area.EcomLanguageId);
72 productImage = p.ImageLarge;
73
74 if (string.IsNullOrWhiteSpace(productImage))
75 {
76 try
77 {
78 var perfionImage = prodService.GetProductFieldValue(p, "AdditionalImages");
79 productImage = $"Files/" + perfionImage.ToString().Split(';')[0];
80 }
81 catch (Exception) { }
82 }
83 }
84
85 bool WithVATBool = Pageview.Area.EcomPricesWithVat == "True";
86 bool pricesWithoutVatForUsers = EcommerceConfiguration.ShowPricesWithoutVatForUsers;
87 bool pricesWithoutVatForValidVat = EcommerceConfiguration.ShowPricesWithoutVatWhenValidVatNumber;
88 if(pricesWithoutVatForUsers && !pricesWithoutVatForValidVat && Pageview.User != null) {
89 WithVATBool = false;
90 }
91 if(pricesWithoutVatForValidVat && Pageview.User != null && !string.IsNullOrWhiteSpace(Pageview.User.VatRegNumber)) {
92 WithVATBool = false;
93 }
94
95 int productDetailPageId = GetPageIdByNavigationTag("ProductOverview");
96 string currentPageUrl = "/Default.aspx?ID=" + Pageview.Page.ID;
97
98 string productNumber = product.Number;
99 string productId = product.Id;
100 string productVariantId = !string.IsNullOrWhiteSpace(product.VariantId) ? product.VariantId : "";
101 string productURL = $"Default.aspx?ID={productDetailPageId}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}";
102 productURL += !string.IsNullOrWhiteSpace(product.VariantId) ? "&VariantID=" + product.VariantId : "";
103 string productManufacturer = product.Manufacturer?.Name ?? "";
104
105 bool isPriceZero = product.Price.Price <= 0;
106 bool hasDiscount = product.Discount.Price > 0;
107 string OriginalPrice = WithVATBool ? product.PriceBeforeDiscount.PriceWithVatFormatted : product.PriceBeforeDiscount.PriceWithoutVatFormatted;
108 string Price = WithVATBool ? product.Price.PriceWithVatFormatted : product.Price.PriceWithoutVatFormatted;
109 string yourDiscount = WithVATBool ? product.Discount.PriceWithVatFormatted : product.Discount.PriceWithoutVatFormatted;
110 double gtmDiscount = WithVATBool ? product.Discount.PriceWithVat : product.Discount.PriceWithoutVat;
111 double gtmPrice = WithVATBool ? product.PriceBeforeDiscount.PriceWithVat : product.PriceBeforeDiscount.PriceWithoutVat;
112 double gtmValue = WithVATBool ? product.Price.PriceWithVat : product.Price.PriceWithoutVat;
113 string ProductdetailPriceSuffixWithVAT = Translate("Productdetail.Price.Suffix.WithVAT", "Incl. VAT");
114 string ProductdetailPriceSuffixWithoutVAT = Translate("Productdetail.Price.Suffix.WithoutVAT", "Excl. VAT");
115 string ProductdetailPriceSuffix = WithVATBool ? ProductdetailPriceSuffixWithVAT : ProductdetailPriceSuffixWithoutVAT;
116 string gtmBrand = !string.IsNullOrWhiteSpace(product.Manufacturer.Name) ? product.Manufacturer.Name.Replace("''", "\\\"").Replace("'", "") : "";
117
118 bool hideStockForGuests = EcommerceConfiguration.HideStockForGuests;
119 string stockFormat = EcommerceConfiguration.StockFormat;
120 bool enableProductStock = hideStockForGuests ? Pageview.User != null : true;
121 string stockText = product.StockStatus;
122 double stockSize = (double)product.StockLevel;
123 bool neverOutOfStock = product.NeverOutOfstock;
124 bool isInStock = stockSize > 0 || neverOutOfStock;
125 string stockClass = isInStock ? "products-module__product-stock-state--instock" : "products-module__product-stock-state--outofstock";
126 string stockSizeFormatted = stockSize.ToString(stockSize % 1 == 0 ? "N0" : "N2", System.Globalization.CultureInfo.GetCultureInfo(Pageview.Area.CultureInfo.TwoLetterISOLanguageName));
127
128 bool hideZeroPrices = EcommerceConfiguration.HideZeroPrices;
129 bool enableAddToCartForZeroPrices = EcommerceConfiguration.AddToCartAllowZeroPrices;
130 bool enableAddToCartForOutOfStock = EcommerceConfiguration.AddToCartAllowOutOfStock;
131
132 bool displayPrice = true;
133 bool enableShoppingCart = true;
134
135 bool enableProductShoppingCart = enableShoppingCart;
136 if(!enableAddToCartForZeroPrices && isPriceZero) {
137 enableProductShoppingCart = false;
138 }
139
140 if(!enableAddToCartForOutOfStock && !isInStock) {
141 enableProductShoppingCart = false;
142 }
143
144 bool displayProductPrice = displayPrice;
145 if(hideZeroPrices && isPriceZero) {
146 displayProductPrice = false;
147 }
148
149 string informativePrice = WithVATBool ? product.PriceInformative.PriceWithVatFormatted : product.PriceInformative.PriceWithoutVatFormatted;
150 if (EcommerceConfiguration.UseInformativePriceAsFromPrice && !string.IsNullOrWhiteSpace(informativePrice))
151 {
152 double informativePriceValue = WithVATBool ? product.PriceInformative.PriceWithVat : product.PriceInformative.PriceWithoutVat;
153 hasDiscount = gtmValue < informativePriceValue;
154 if (hasDiscount)
155 {
156 OriginalPrice = informativePrice;
157 double yourProfitValue = informativePriceValue - gtmValue;
158 yourDiscount = WithVATBool ? new PriceInfo { PriceWithVAT = yourProfitValue }.PriceWithVATFormatted : new PriceInfo { PriceWithoutVAT = yourProfitValue }.PriceWithoutVATFormatted;
159 }
160 }
161
162 string retailPrice = "";
163 bool displayRetailPrice = EcommerceConfiguration.DisplayRetailPrice;
164 if(EcommerceConfiguration.DisplayRetailPriceForUsers && Pageview.User == null) {
165 displayRetailPrice = false;
166 }
167 if(displayRetailPrice) {
168 string priceFieldName = EcommerceConfiguration.RetailPriceField;
169 if(EcommerceConfiguration.RetailPriceIsDbPrice) {
170 var prodService = new Dynamicweb.Ecommerce.Products.ProductService();
171 var p = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, product.VariantId, Pageview.Area.EcomLanguageId);
172 PriceContext customerPriceContext = new PriceContext(Dynamicweb.Ecommerce.Common.Context.Currency, Dynamicweb.Ecommerce.Common.Context.Country, null, null, Dynamicweb.Ecommerce.Common.Context.ReverseChargeForVatEnabled, DateTime.Now);
173 var customerPrice = p?.GetPrice(customerPriceContext);
174 if(customerPrice.Price > 0) {
175 retailPrice = WithVATBool ? customerPrice.PriceWithVATFormatted : customerPrice.PriceWithoutVATFormatted;
176 }
177 } else if(!string.IsNullOrWhiteSpace(priceFieldName)) {
178 double customerPriceValue = 0.0;
179 if (product.ProductFields.TryGetValue(priceFieldName, out var fieldValue) && fieldValue.Value is double) {
180 customerPriceValue = (double)fieldValue.Value;
181 }
182 if(customerPriceValue > 0) {
183 retailPrice = WithVATBool ? new PriceInfo { PriceWithVAT = customerPriceValue }.PriceWithVATFormatted : new PriceInfo { PriceWithoutVAT = customerPriceValue }.PriceWithoutVATFormatted;
184 }
185 }
186 }
187
188 string yourProfitLabel = Translate("Productdetail.YourProfitLabel", "Uw voordeel:");
189
190 List<FieldOptionValueViewModel> productRibbons = null;
191 if (product.ProductFields["ProductRibbon"] != null)
192 {
193 productRibbons = (List<FieldOptionValueViewModel>)product.ProductFields["ProductRibbon"].Value;
194 }
195
196 <li class="products-module__slider-cell">
197 <div class="products-module products-module__slider-cell__innerwrapper">
198
199 @foreach(var rib in productRibbons) {
200 <p class="products-module__ribbon">
201 <span class="products-module__ribbon-text">@rib.Value</span>
202 </p>
203 }
204
205 <figure class="products-module__image-container">
206 @if(!string.IsNullOrWhiteSpace(productImage))
207 {
208 <img src="/Admin/Public/GetImage.ashx?Image=@productImage&Crop=7&Format=webp&Quality=90&Compression=80&Height=200" alt="@productName" loading="lazy" height="200" width="300" />
209 }
210 </figure>
211
212 <h3 class="products-module__product-name">
213 @if(!string.IsNullOrWhiteSpace(productManufacturer))
214 {
215 <span class="products-module__product-name--manufacturer">@productManufacturer</span>
216 }
217 <span class="products-module__product-name--product">@productName</span>
218 </h3>
219
220 @if(!string.IsNullOrWhiteSpace(productNumber))
221 {
222 <p class="products-module__product-article-number">@productNumber</p>
223 }
224
225 @*
226 @if (productCommentCount > 0)
227 {
228 <div class="products-module__product-review-indicator">
229 @renderReviewIndicator("gold", productRating, "row", true, productCommentCount)
230 </div>
231 }
232 *@
233
234 @if (displayPrice && displayProductPrice)
235 {
236 <div class="products-module__product-price-container">
237 @if (hasDiscount)
238 {
239 <span class="products-module__product-price-original">@OriginalPrice</span>
240 <span class="products-module__product-price">@Price</span>
241 }
242 else
243 {
244 <span class="products-module__product-price">@OriginalPrice</span>
245 }
246 <span class="products-module__product-price-suffix">@ProductdetailPriceSuffix</span>
247 @if (!string.IsNullOrWhiteSpace(retailPrice))
248 {
249 <p class="products-module__product-retail-price">
250 @String.Format(Translate("ProductBlockTitle.RetailPrice", "Retail price: {0}"), retailPrice)
251 </p>
252 }
253 @if (hasDiscount)
254 {
255 <p class="products-module__product-your-discount">@Translate("Productdetail.YourProfitLabel", "Uw voordeel:") @yourDiscount</p>
256 }
257 </div>
258 }
259
260 <section class="products-module__product-actions">
261 @if (enableProductStock && !string.IsNullOrWhiteSpace(stockFormat))
262 {
263 if(stockFormat == "text") {
264 if (!string.IsNullOrWhiteSpace(stockText))
265 {
266 <p class="products-module__product-stock-state @stockClass">@string.Format(stockText, stockSize)</p>
267 }
268 }
269 else
270 {
271 string translationTag = "";
272 if(neverOutOfStock)
273 {
274 translationTag = Translate("ProductBlockStockInfo.AmountInStock", "In stock");
275 }
276 else if(stockSize == 1)
277 {
278 translationTag = Translate("ProductBlockStockInfo.AmountInStockSingle", "{0} product in stock");
279 }
280 else if(stockSize > 1)
281 {
282 translationTag = Translate("ProductBlockStockInfo.AmountInStockMultiple", "{0} products in stock");
283 }
284 else if(!isInStock)
285 {
286 translationTag = Translate("ProductBlockStockInfo.AmountOutOfStock", "Out of stock");
287 }
288 <p class="products-module__product-stock-state @stockClass">@string.Format(translationTag, stockSizeFormatted)</p>
289 }
290 }
291
292 @if(enableShoppingCart && enableProductShoppingCart && !isPriceZero)
293 {
294 <add-to-cart
295 class="app-addtocart"
296 data-prodid="@productId"
297 data-variantid="@productVariantId"
298 data-show-text="False"
299 data-min-quantity="@product.PurchaseMinimumQuantity"
300 data-step="@product.PurchaseQuantityStep"
301 data-list-id="@listId"
302 data-list-name="@listName">
303 </add-to-cart>
304 }
305 else
306 {
307 <button class="products-module__more-infomation">@Translate("ProductsModule.MoreInformation", "More information")</button>
308 }
309 </section>
310
311 <a href="@productURL" class="products-module__link" data-id="@productId" data-variantid="@productVariantId" data-number="@productNumber" data-name='@productName.Replace("''", "\\\"").Replace("'", "")' data-position="@index" data-brand='@gtmBrand' data-category='@product.PrimaryOrDefaultGroup.Name.Replace("''", "\\\"").Replace("'", "")' data-listid="@listId" data-listname="@listName" data-gtmprice="@gtmPrice" data-gtmdiscount="@gtmDiscount" data-gtmvalue="@gtmValue" data-currencycode="@Dynamicweb.Ecommerce.Common.Context.Currency.Code" aria-label="@productName"></a>
312 </div>
313 </li>
314 }
315
316 @helper renderProductListEnhancedEcom(string listId, string listName, IEnumerable<ProductViewModel> products) {
317 var index = 1;
318 <text>
319 <script>
320 if(window.dataLayer) {
321 dataLayer.push({
322 'event': 'view_item_list',
323 'ecommerce': {
324 'item_list_id': '@listId',
325 'item_list_name': '@listName',
326 'items': [
327 @foreach (var product in products) {
328 string pName = product.Name.Replace("''", "\\\"").Replace("'", "");
329 string pGroupName = product.PrimaryOrDefaultGroup?.Name?.Replace("''", "\\\"").Replace("'", "");
330 string pBrand = product.Manufacturer?.Name?.Replace("''", "\\\"").Replace("'", "");
331 <text>
332 {
333 'item_id': '@product.Id',
334 'item_name': '@pName',
335 'item_number': '@product.Number',
336 'discount': @product.Discount.Price,
337 'index': @index,
338 'item_brand': '@pBrand',
339 'item_category': '@pGroupName',
340 'item_list_id': '@listId',
341 'item_list_name': '@listName',
342 'item_variant': '@product.VariantId',
343 'price': @product.Price.Price,
344 'quantity': 1,
345 },
346 </text>
347 index++;
348 }
349 ]
350 }
351 });
352 }
353 </script>
354 </text>
355 }
356
Error executing template "Designs/ClientBase_generated/Paragraph/ProductDetailWidgetRelatedProducts.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass6_0.<GetRelatedGroups>b__1(IGrouping`2 group)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at System.Lazy`1.CreateValue()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Lazy`1.get_Value()
at CompiledRazorTemplates.Dynamic.RazorEngine_d4de60c65a7341b2a32b8c10f12d43b5.Execute() in D:\dynamicweb.net\Solutions\Bluedesk\koksgroup.cloud.dynamicweb-cms.com\files\Templates\Designs\ClientBase_generated\Paragraph\ProductDetailWidgetRelatedProducts.cshtml:line 25
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 Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel>
2 @using Dynamicweb.Ecommerce.Prices;
3 @using Dynamicweb.Ecommerce.ProductCatalog;
4 @using Bluedesk.DynamicWeb.ItemTypes.BaseSolution;
5 @using Bluedesk.DynamicWeb.ItemTypes.Settings.Configuration;
6
7 @{
8 string paragraphID = Pageview.CurrentParagraph.ID.ToString();
9 ProductDetailWidgetRelatedProducts _data = Dynamicweb.Services.Items.GetItem("ProductDetailWidgetRelatedProducts", Model.ItemId).ToCodeFirstItem<ProductDetailWidgetRelatedProducts>() ?? new ProductDetailWidgetRelatedProducts();
10
11 ProductViewModel product = new ProductViewModel();
12 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
13 {
14 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
15 }
16
17 var selectedGroups = _data.SelectedGroups;
18
19 string ElementID = !string.IsNullOrWhiteSpace(_data.CustomID) ? _data.CustomID : paragraphID;
20
21 }
22
23 <section id="@ElementID" class="pdp-paragraph pdp-related-products-widget @_data.CssClass">
24 @foreach(var selectedGroup in selectedGroups) {
25 RelatedGroupViewModel relatedGroup = product?.RelatedGroups?.FirstOrDefault(obj => obj.Id == selectedGroup.RelatedGroupID);
26 if (relatedGroup != null)
27 {
28 IEnumerable<ProductViewModel> relatedProducts = relatedGroup.GetRelatedProducts();
29 string groupName = Translate("ProductRelatedGroup." + relatedGroup.Name.Replace(" ", ""), relatedGroup.Name);
30
31 string CustomID = !string.IsNullOrWhiteSpace(_data.CustomID) ? $"id='{_data.CustomID}'" : "";
32
33 if (relatedProducts.Any())
34 {
35 var index = 1;
36 <section class="products-module__container @selectedGroup.CssClass" @CustomID>
37 <div class="container">
38
39 <header class="products-module__header">
40 <h2 class="products-module__title">@groupName</h2>
41 </header>
42
43 <ul class="products-module__slider">
44 @foreach (var p in relatedProducts)
45 {
46 @renderProductBlock(p, relatedGroup.Name, relatedGroup.Id, index);
47 index++;
48 }
49 </ul>
50 </div>
51 </section>
52
53 @renderProductListEnhancedEcom(relatedGroup.Id, relatedGroup.Name, relatedProducts)
54 }
55 }
56 }
57 </section>
58
59 @helper renderProductBlock(Dynamicweb.Ecommerce.ProductCatalog.ProductViewModel product, string listId, string listName, int index)
60 {
61 var master_configuration = Dynamicweb.Services.Pages.GetPageByNavigationTag(Pageview.AreaID, "MasterConfiguration");
62 MasterConfig mc = master_configuration.Item.ToCodeFirstItem<MasterConfig>();
63 EcomConfig EcommerceConfiguration = mc.EcomConfiguration;
64
65 string productName = product.Name;
66 string productImage = product.DefaultImage?.Value ?? "";
67
68 if (string.IsNullOrWhiteSpace(productImage))
69 {
70 var prodService = new Dynamicweb.Ecommerce.Products.ProductService();
71 var p = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, product.VariantId, Pageview.Area.EcomLanguageId);
72 productImage = p.ImageLarge;
73
74 if (string.IsNullOrWhiteSpace(productImage))
75 {
76 try
77 {
78 var perfionImage = prodService.GetProductFieldValue(p, "AdditionalImages");
79 productImage = $"Files/" + perfionImage.ToString().Split(';')[0];
80 }
81 catch (Exception) { }
82 }
83 }
84
85 bool WithVATBool = Pageview.Area.EcomPricesWithVat == "True";
86 bool pricesWithoutVatForUsers = EcommerceConfiguration.ShowPricesWithoutVatForUsers;
87 bool pricesWithoutVatForValidVat = EcommerceConfiguration.ShowPricesWithoutVatWhenValidVatNumber;
88 if(pricesWithoutVatForUsers && !pricesWithoutVatForValidVat && Pageview.User != null) {
89 WithVATBool = false;
90 }
91 if(pricesWithoutVatForValidVat && Pageview.User != null && !string.IsNullOrWhiteSpace(Pageview.User.VatRegNumber)) {
92 WithVATBool = false;
93 }
94
95 int productDetailPageId = GetPageIdByNavigationTag("ProductOverview");
96 string currentPageUrl = "/Default.aspx?ID=" + Pageview.Page.ID;
97
98 string productNumber = product.Number;
99 string productId = product.Id;
100 string productVariantId = !string.IsNullOrWhiteSpace(product.VariantId) ? product.VariantId : "";
101 string productURL = $"Default.aspx?ID={productDetailPageId}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}";
102 productURL += !string.IsNullOrWhiteSpace(product.VariantId) ? "&VariantID=" + product.VariantId : "";
103 string productManufacturer = product.Manufacturer?.Name ?? "";
104
105 bool isPriceZero = product.Price.Price <= 0;
106 bool hasDiscount = product.Discount.Price > 0;
107 string OriginalPrice = WithVATBool ? product.PriceBeforeDiscount.PriceWithVatFormatted : product.PriceBeforeDiscount.PriceWithoutVatFormatted;
108 string Price = WithVATBool ? product.Price.PriceWithVatFormatted : product.Price.PriceWithoutVatFormatted;
109 string yourDiscount = WithVATBool ? product.Discount.PriceWithVatFormatted : product.Discount.PriceWithoutVatFormatted;
110 double gtmDiscount = WithVATBool ? product.Discount.PriceWithVat : product.Discount.PriceWithoutVat;
111 double gtmPrice = WithVATBool ? product.PriceBeforeDiscount.PriceWithVat : product.PriceBeforeDiscount.PriceWithoutVat;
112 double gtmValue = WithVATBool ? product.Price.PriceWithVat : product.Price.PriceWithoutVat;
113 string ProductdetailPriceSuffixWithVAT = Translate("Productdetail.Price.Suffix.WithVAT", "Incl. VAT");
114 string ProductdetailPriceSuffixWithoutVAT = Translate("Productdetail.Price.Suffix.WithoutVAT", "Excl. VAT");
115 string ProductdetailPriceSuffix = WithVATBool ? ProductdetailPriceSuffixWithVAT : ProductdetailPriceSuffixWithoutVAT;
116 string gtmBrand = !string.IsNullOrWhiteSpace(product.Manufacturer.Name) ? product.Manufacturer.Name.Replace("''", "\\\"").Replace("'", "") : "";
117
118 bool hideStockForGuests = EcommerceConfiguration.HideStockForGuests;
119 string stockFormat = EcommerceConfiguration.StockFormat;
120 bool enableProductStock = hideStockForGuests ? Pageview.User != null : true;
121 string stockText = product.StockStatus;
122 double stockSize = (double)product.StockLevel;
123 bool neverOutOfStock = product.NeverOutOfstock;
124 bool isInStock = stockSize > 0 || neverOutOfStock;
125 string stockClass = isInStock ? "products-module__product-stock-state--instock" : "products-module__product-stock-state--outofstock";
126 string stockSizeFormatted = stockSize.ToString(stockSize % 1 == 0 ? "N0" : "N2", System.Globalization.CultureInfo.GetCultureInfo(Pageview.Area.CultureInfo.TwoLetterISOLanguageName));
127
128 bool hideZeroPrices = EcommerceConfiguration.HideZeroPrices;
129 bool enableAddToCartForZeroPrices = EcommerceConfiguration.AddToCartAllowZeroPrices;
130 bool enableAddToCartForOutOfStock = EcommerceConfiguration.AddToCartAllowOutOfStock;
131
132 bool displayPrice = true;
133 bool enableShoppingCart = true;
134
135 bool enableProductShoppingCart = enableShoppingCart;
136 if(!enableAddToCartForZeroPrices && isPriceZero) {
137 enableProductShoppingCart = false;
138 }
139
140 if(!enableAddToCartForOutOfStock && !isInStock) {
141 enableProductShoppingCart = false;
142 }
143
144 bool displayProductPrice = displayPrice;
145 if(hideZeroPrices && isPriceZero) {
146 displayProductPrice = false;
147 }
148
149 string informativePrice = WithVATBool ? product.PriceInformative.PriceWithVatFormatted : product.PriceInformative.PriceWithoutVatFormatted;
150 if (EcommerceConfiguration.UseInformativePriceAsFromPrice && !string.IsNullOrWhiteSpace(informativePrice))
151 {
152 double informativePriceValue = WithVATBool ? product.PriceInformative.PriceWithVat : product.PriceInformative.PriceWithoutVat;
153 hasDiscount = gtmValue < informativePriceValue;
154 if (hasDiscount)
155 {
156 OriginalPrice = informativePrice;
157 double yourProfitValue = informativePriceValue - gtmValue;
158 yourDiscount = WithVATBool ? new PriceInfo { PriceWithVAT = yourProfitValue }.PriceWithVATFormatted : new PriceInfo { PriceWithoutVAT = yourProfitValue }.PriceWithoutVATFormatted;
159 }
160 }
161
162 string retailPrice = "";
163 bool displayRetailPrice = EcommerceConfiguration.DisplayRetailPrice;
164 if(EcommerceConfiguration.DisplayRetailPriceForUsers && Pageview.User == null) {
165 displayRetailPrice = false;
166 }
167 if(displayRetailPrice) {
168 string priceFieldName = EcommerceConfiguration.RetailPriceField;
169 if(EcommerceConfiguration.RetailPriceIsDbPrice) {
170 var prodService = new Dynamicweb.Ecommerce.Products.ProductService();
171 var p = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, product.VariantId, Pageview.Area.EcomLanguageId);
172 PriceContext customerPriceContext = new PriceContext(Dynamicweb.Ecommerce.Common.Context.Currency, Dynamicweb.Ecommerce.Common.Context.Country, null, null, Dynamicweb.Ecommerce.Common.Context.ReverseChargeForVatEnabled, DateTime.Now);
173 var customerPrice = p?.GetPrice(customerPriceContext);
174 if(customerPrice.Price > 0) {
175 retailPrice = WithVATBool ? customerPrice.PriceWithVATFormatted : customerPrice.PriceWithoutVATFormatted;
176 }
177 } else if(!string.IsNullOrWhiteSpace(priceFieldName)) {
178 double customerPriceValue = 0.0;
179 if (product.ProductFields.TryGetValue(priceFieldName, out var fieldValue) && fieldValue.Value is double) {
180 customerPriceValue = (double)fieldValue.Value;
181 }
182 if(customerPriceValue > 0) {
183 retailPrice = WithVATBool ? new PriceInfo { PriceWithVAT = customerPriceValue }.PriceWithVATFormatted : new PriceInfo { PriceWithoutVAT = customerPriceValue }.PriceWithoutVATFormatted;
184 }
185 }
186 }
187
188 string yourProfitLabel = Translate("Productdetail.YourProfitLabel", "Uw voordeel:");
189
190 List<FieldOptionValueViewModel> productRibbons = null;
191 if (product.ProductFields["ProductRibbon"] != null)
192 {
193 productRibbons = (List<FieldOptionValueViewModel>)product.ProductFields["ProductRibbon"].Value;
194 }
195
196 <li class="products-module__slider-cell">
197 <div class="products-module products-module__slider-cell__innerwrapper">
198
199 @foreach(var rib in productRibbons) {
200 <p class="products-module__ribbon">
201 <span class="products-module__ribbon-text">@rib.Value</span>
202 </p>
203 }
204
205 <figure class="products-module__image-container">
206 @if(!string.IsNullOrWhiteSpace(productImage))
207 {
208 <img src="/Admin/Public/GetImage.ashx?Image=@productImage&Crop=7&Format=webp&Quality=90&Compression=80&Height=200" alt="@productName" loading="lazy" height="200" width="300" />
209 }
210 </figure>
211
212 <h3 class="products-module__product-name">
213 @if(!string.IsNullOrWhiteSpace(productManufacturer))
214 {
215 <span class="products-module__product-name--manufacturer">@productManufacturer</span>
216 }
217 <span class="products-module__product-name--product">@productName</span>
218 </h3>
219
220 @if(!string.IsNullOrWhiteSpace(productNumber))
221 {
222 <p class="products-module__product-article-number">@productNumber</p>
223 }
224
225 @*
226 @if (productCommentCount > 0)
227 {
228 <div class="products-module__product-review-indicator">
229 @renderReviewIndicator("gold", productRating, "row", true, productCommentCount)
230 </div>
231 }
232 *@
233
234 @if (displayPrice && displayProductPrice)
235 {
236 <div class="products-module__product-price-container">
237 @if (hasDiscount)
238 {
239 <span class="products-module__product-price-original">@OriginalPrice</span>
240 <span class="products-module__product-price">@Price</span>
241 }
242 else
243 {
244 <span class="products-module__product-price">@OriginalPrice</span>
245 }
246 <span class="products-module__product-price-suffix">@ProductdetailPriceSuffix</span>
247 @if (!string.IsNullOrWhiteSpace(retailPrice))
248 {
249 <p class="products-module__product-retail-price">
250 @String.Format(Translate("ProductBlockTitle.RetailPrice", "Retail price: {0}"), retailPrice)
251 </p>
252 }
253 @if (hasDiscount)
254 {
255 <p class="products-module__product-your-discount">@Translate("Productdetail.YourProfitLabel", "Uw voordeel:") @yourDiscount</p>
256 }
257 </div>
258 }
259
260 <section class="products-module__product-actions">
261 @if (enableProductStock && !string.IsNullOrWhiteSpace(stockFormat))
262 {
263 if(stockFormat == "text") {
264 if (!string.IsNullOrWhiteSpace(stockText))
265 {
266 <p class="products-module__product-stock-state @stockClass">@string.Format(stockText, stockSize)</p>
267 }
268 }
269 else
270 {
271 string translationTag = "";
272 if(neverOutOfStock)
273 {
274 translationTag = Translate("ProductBlockStockInfo.AmountInStock", "In stock");
275 }
276 else if(stockSize == 1)
277 {
278 translationTag = Translate("ProductBlockStockInfo.AmountInStockSingle", "{0} product in stock");
279 }
280 else if(stockSize > 1)
281 {
282 translationTag = Translate("ProductBlockStockInfo.AmountInStockMultiple", "{0} products in stock");
283 }
284 else if(!isInStock)
285 {
286 translationTag = Translate("ProductBlockStockInfo.AmountOutOfStock", "Out of stock");
287 }
288 <p class="products-module__product-stock-state @stockClass">@string.Format(translationTag, stockSizeFormatted)</p>
289 }
290 }
291
292 @if(enableShoppingCart && enableProductShoppingCart && !isPriceZero)
293 {
294 <add-to-cart
295 class="app-addtocart"
296 data-prodid="@productId"
297 data-variantid="@productVariantId"
298 data-show-text="False"
299 data-min-quantity="@product.PurchaseMinimumQuantity"
300 data-step="@product.PurchaseQuantityStep"
301 data-list-id="@listId"
302 data-list-name="@listName">
303 </add-to-cart>
304 }
305 else
306 {
307 <button class="products-module__more-infomation">@Translate("ProductsModule.MoreInformation", "More information")</button>
308 }
309 </section>
310
311 <a href="@productURL" class="products-module__link" data-id="@productId" data-variantid="@productVariantId" data-number="@productNumber" data-name='@productName.Replace("''", "\\\"").Replace("'", "")' data-position="@index" data-brand='@gtmBrand' data-category='@product.PrimaryOrDefaultGroup.Name.Replace("''", "\\\"").Replace("'", "")' data-listid="@listId" data-listname="@listName" data-gtmprice="@gtmPrice" data-gtmdiscount="@gtmDiscount" data-gtmvalue="@gtmValue" data-currencycode="@Dynamicweb.Ecommerce.Common.Context.Currency.Code" aria-label="@productName"></a>
312 </div>
313 </li>
314 }
315
316 @helper renderProductListEnhancedEcom(string listId, string listName, IEnumerable<ProductViewModel> products) {
317 var index = 1;
318 <text>
319 <script>
320 if(window.dataLayer) {
321 dataLayer.push({
322 'event': 'view_item_list',
323 'ecommerce': {
324 'item_list_id': '@listId',
325 'item_list_name': '@listName',
326 'items': [
327 @foreach (var product in products) {
328 string pName = product.Name.Replace("''", "\\\"").Replace("'", "");
329 string pGroupName = product.PrimaryOrDefaultGroup?.Name?.Replace("''", "\\\"").Replace("'", "");
330 string pBrand = product.Manufacturer?.Name?.Replace("''", "\\\"").Replace("'", "");
331 <text>
332 {
333 'item_id': '@product.Id',
334 'item_name': '@pName',
335 'item_number': '@product.Number',
336 'discount': @product.Discount.Price,
337 'index': @index,
338 'item_brand': '@pBrand',
339 'item_category': '@pGroupName',
340 'item_list_id': '@listId',
341 'item_list_name': '@listName',
342 'item_variant': '@product.VariantId',
343 'price': @product.Price.Price,
344 'quantity': 1,
345 },
346 </text>
347 index++;
348 }
349 ]
350 }
351 });
352 }
353 </script>
354 </text>
355 }
356
Error executing template "Designs/ClientBase_generated/Paragraph/ProductDetailWidgetRelatedProducts.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass6_0.<GetRelatedGroups>b__1(IGrouping`2 group)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at System.Lazy`1.CreateValue()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Lazy`1.get_Value()
at CompiledRazorTemplates.Dynamic.RazorEngine_d4de60c65a7341b2a32b8c10f12d43b5.Execute() in D:\dynamicweb.net\Solutions\Bluedesk\koksgroup.cloud.dynamicweb-cms.com\files\Templates\Designs\ClientBase_generated\Paragraph\ProductDetailWidgetRelatedProducts.cshtml:line 25
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 Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel>
2 @using Dynamicweb.Ecommerce.Prices;
3 @using Dynamicweb.Ecommerce.ProductCatalog;
4 @using Bluedesk.DynamicWeb.ItemTypes.BaseSolution;
5 @using Bluedesk.DynamicWeb.ItemTypes.Settings.Configuration;
6
7 @{
8 string paragraphID = Pageview.CurrentParagraph.ID.ToString();
9 ProductDetailWidgetRelatedProducts _data = Dynamicweb.Services.Items.GetItem("ProductDetailWidgetRelatedProducts", Model.ItemId).ToCodeFirstItem<ProductDetailWidgetRelatedProducts>() ?? new ProductDetailWidgetRelatedProducts();
10
11 ProductViewModel product = new ProductViewModel();
12 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
13 {
14 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
15 }
16
17 var selectedGroups = _data.SelectedGroups;
18
19 string ElementID = !string.IsNullOrWhiteSpace(_data.CustomID) ? _data.CustomID : paragraphID;
20
21 }
22
23 <section id="@ElementID" class="pdp-paragraph pdp-related-products-widget @_data.CssClass">
24 @foreach(var selectedGroup in selectedGroups) {
25 RelatedGroupViewModel relatedGroup = product?.RelatedGroups?.FirstOrDefault(obj => obj.Id == selectedGroup.RelatedGroupID);
26 if (relatedGroup != null)
27 {
28 IEnumerable<ProductViewModel> relatedProducts = relatedGroup.GetRelatedProducts();
29 string groupName = Translate("ProductRelatedGroup." + relatedGroup.Name.Replace(" ", ""), relatedGroup.Name);
30
31 string CustomID = !string.IsNullOrWhiteSpace(_data.CustomID) ? $"id='{_data.CustomID}'" : "";
32
33 if (relatedProducts.Any())
34 {
35 var index = 1;
36 <section class="products-module__container @selectedGroup.CssClass" @CustomID>
37 <div class="container">
38
39 <header class="products-module__header">
40 <h2 class="products-module__title">@groupName</h2>
41 </header>
42
43 <ul class="products-module__slider">
44 @foreach (var p in relatedProducts)
45 {
46 @renderProductBlock(p, relatedGroup.Name, relatedGroup.Id, index);
47 index++;
48 }
49 </ul>
50 </div>
51 </section>
52
53 @renderProductListEnhancedEcom(relatedGroup.Id, relatedGroup.Name, relatedProducts)
54 }
55 }
56 }
57 </section>
58
59 @helper renderProductBlock(Dynamicweb.Ecommerce.ProductCatalog.ProductViewModel product, string listId, string listName, int index)
60 {
61 var master_configuration = Dynamicweb.Services.Pages.GetPageByNavigationTag(Pageview.AreaID, "MasterConfiguration");
62 MasterConfig mc = master_configuration.Item.ToCodeFirstItem<MasterConfig>();
63 EcomConfig EcommerceConfiguration = mc.EcomConfiguration;
64
65 string productName = product.Name;
66 string productImage = product.DefaultImage?.Value ?? "";
67
68 if (string.IsNullOrWhiteSpace(productImage))
69 {
70 var prodService = new Dynamicweb.Ecommerce.Products.ProductService();
71 var p = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, product.VariantId, Pageview.Area.EcomLanguageId);
72 productImage = p.ImageLarge;
73
74 if (string.IsNullOrWhiteSpace(productImage))
75 {
76 try
77 {
78 var perfionImage = prodService.GetProductFieldValue(p, "AdditionalImages");
79 productImage = $"Files/" + perfionImage.ToString().Split(';')[0];
80 }
81 catch (Exception) { }
82 }
83 }
84
85 bool WithVATBool = Pageview.Area.EcomPricesWithVat == "True";
86 bool pricesWithoutVatForUsers = EcommerceConfiguration.ShowPricesWithoutVatForUsers;
87 bool pricesWithoutVatForValidVat = EcommerceConfiguration.ShowPricesWithoutVatWhenValidVatNumber;
88 if(pricesWithoutVatForUsers && !pricesWithoutVatForValidVat && Pageview.User != null) {
89 WithVATBool = false;
90 }
91 if(pricesWithoutVatForValidVat && Pageview.User != null && !string.IsNullOrWhiteSpace(Pageview.User.VatRegNumber)) {
92 WithVATBool = false;
93 }
94
95 int productDetailPageId = GetPageIdByNavigationTag("ProductOverview");
96 string currentPageUrl = "/Default.aspx?ID=" + Pageview.Page.ID;
97
98 string productNumber = product.Number;
99 string productId = product.Id;
100 string productVariantId = !string.IsNullOrWhiteSpace(product.VariantId) ? product.VariantId : "";
101 string productURL = $"Default.aspx?ID={productDetailPageId}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}";
102 productURL += !string.IsNullOrWhiteSpace(product.VariantId) ? "&VariantID=" + product.VariantId : "";
103 string productManufacturer = product.Manufacturer?.Name ?? "";
104
105 bool isPriceZero = product.Price.Price <= 0;
106 bool hasDiscount = product.Discount.Price > 0;
107 string OriginalPrice = WithVATBool ? product.PriceBeforeDiscount.PriceWithVatFormatted : product.PriceBeforeDiscount.PriceWithoutVatFormatted;
108 string Price = WithVATBool ? product.Price.PriceWithVatFormatted : product.Price.PriceWithoutVatFormatted;
109 string yourDiscount = WithVATBool ? product.Discount.PriceWithVatFormatted : product.Discount.PriceWithoutVatFormatted;
110 double gtmDiscount = WithVATBool ? product.Discount.PriceWithVat : product.Discount.PriceWithoutVat;
111 double gtmPrice = WithVATBool ? product.PriceBeforeDiscount.PriceWithVat : product.PriceBeforeDiscount.PriceWithoutVat;
112 double gtmValue = WithVATBool ? product.Price.PriceWithVat : product.Price.PriceWithoutVat;
113 string ProductdetailPriceSuffixWithVAT = Translate("Productdetail.Price.Suffix.WithVAT", "Incl. VAT");
114 string ProductdetailPriceSuffixWithoutVAT = Translate("Productdetail.Price.Suffix.WithoutVAT", "Excl. VAT");
115 string ProductdetailPriceSuffix = WithVATBool ? ProductdetailPriceSuffixWithVAT : ProductdetailPriceSuffixWithoutVAT;
116 string gtmBrand = !string.IsNullOrWhiteSpace(product.Manufacturer.Name) ? product.Manufacturer.Name.Replace("''", "\\\"").Replace("'", "") : "";
117
118 bool hideStockForGuests = EcommerceConfiguration.HideStockForGuests;
119 string stockFormat = EcommerceConfiguration.StockFormat;
120 bool enableProductStock = hideStockForGuests ? Pageview.User != null : true;
121 string stockText = product.StockStatus;
122 double stockSize = (double)product.StockLevel;
123 bool neverOutOfStock = product.NeverOutOfstock;
124 bool isInStock = stockSize > 0 || neverOutOfStock;
125 string stockClass = isInStock ? "products-module__product-stock-state--instock" : "products-module__product-stock-state--outofstock";
126 string stockSizeFormatted = stockSize.ToString(stockSize % 1 == 0 ? "N0" : "N2", System.Globalization.CultureInfo.GetCultureInfo(Pageview.Area.CultureInfo.TwoLetterISOLanguageName));
127
128 bool hideZeroPrices = EcommerceConfiguration.HideZeroPrices;
129 bool enableAddToCartForZeroPrices = EcommerceConfiguration.AddToCartAllowZeroPrices;
130 bool enableAddToCartForOutOfStock = EcommerceConfiguration.AddToCartAllowOutOfStock;
131
132 bool displayPrice = true;
133 bool enableShoppingCart = true;
134
135 bool enableProductShoppingCart = enableShoppingCart;
136 if(!enableAddToCartForZeroPrices && isPriceZero) {
137 enableProductShoppingCart = false;
138 }
139
140 if(!enableAddToCartForOutOfStock && !isInStock) {
141 enableProductShoppingCart = false;
142 }
143
144 bool displayProductPrice = displayPrice;
145 if(hideZeroPrices && isPriceZero) {
146 displayProductPrice = false;
147 }
148
149 string informativePrice = WithVATBool ? product.PriceInformative.PriceWithVatFormatted : product.PriceInformative.PriceWithoutVatFormatted;
150 if (EcommerceConfiguration.UseInformativePriceAsFromPrice && !string.IsNullOrWhiteSpace(informativePrice))
151 {
152 double informativePriceValue = WithVATBool ? product.PriceInformative.PriceWithVat : product.PriceInformative.PriceWithoutVat;
153 hasDiscount = gtmValue < informativePriceValue;
154 if (hasDiscount)
155 {
156 OriginalPrice = informativePrice;
157 double yourProfitValue = informativePriceValue - gtmValue;
158 yourDiscount = WithVATBool ? new PriceInfo { PriceWithVAT = yourProfitValue }.PriceWithVATFormatted : new PriceInfo { PriceWithoutVAT = yourProfitValue }.PriceWithoutVATFormatted;
159 }
160 }
161
162 string retailPrice = "";
163 bool displayRetailPrice = EcommerceConfiguration.DisplayRetailPrice;
164 if(EcommerceConfiguration.DisplayRetailPriceForUsers && Pageview.User == null) {
165 displayRetailPrice = false;
166 }
167 if(displayRetailPrice) {
168 string priceFieldName = EcommerceConfiguration.RetailPriceField;
169 if(EcommerceConfiguration.RetailPriceIsDbPrice) {
170 var prodService = new Dynamicweb.Ecommerce.Products.ProductService();
171 var p = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, product.VariantId, Pageview.Area.EcomLanguageId);
172 PriceContext customerPriceContext = new PriceContext(Dynamicweb.Ecommerce.Common.Context.Currency, Dynamicweb.Ecommerce.Common.Context.Country, null, null, Dynamicweb.Ecommerce.Common.Context.ReverseChargeForVatEnabled, DateTime.Now);
173 var customerPrice = p?.GetPrice(customerPriceContext);
174 if(customerPrice.Price > 0) {
175 retailPrice = WithVATBool ? customerPrice.PriceWithVATFormatted : customerPrice.PriceWithoutVATFormatted;
176 }
177 } else if(!string.IsNullOrWhiteSpace(priceFieldName)) {
178 double customerPriceValue = 0.0;
179 if (product.ProductFields.TryGetValue(priceFieldName, out var fieldValue) && fieldValue.Value is double) {
180 customerPriceValue = (double)fieldValue.Value;
181 }
182 if(customerPriceValue > 0) {
183 retailPrice = WithVATBool ? new PriceInfo { PriceWithVAT = customerPriceValue }.PriceWithVATFormatted : new PriceInfo { PriceWithoutVAT = customerPriceValue }.PriceWithoutVATFormatted;
184 }
185 }
186 }
187
188 string yourProfitLabel = Translate("Productdetail.YourProfitLabel", "Uw voordeel:");
189
190 List<FieldOptionValueViewModel> productRibbons = null;
191 if (product.ProductFields["ProductRibbon"] != null)
192 {
193 productRibbons = (List<FieldOptionValueViewModel>)product.ProductFields["ProductRibbon"].Value;
194 }
195
196 <li class="products-module__slider-cell">
197 <div class="products-module products-module__slider-cell__innerwrapper">
198
199 @foreach(var rib in productRibbons) {
200 <p class="products-module__ribbon">
201 <span class="products-module__ribbon-text">@rib.Value</span>
202 </p>
203 }
204
205 <figure class="products-module__image-container">
206 @if(!string.IsNullOrWhiteSpace(productImage))
207 {
208 <img src="/Admin/Public/GetImage.ashx?Image=@productImage&Crop=7&Format=webp&Quality=90&Compression=80&Height=200" alt="@productName" loading="lazy" height="200" width="300" />
209 }
210 </figure>
211
212 <h3 class="products-module__product-name">
213 @if(!string.IsNullOrWhiteSpace(productManufacturer))
214 {
215 <span class="products-module__product-name--manufacturer">@productManufacturer</span>
216 }
217 <span class="products-module__product-name--product">@productName</span>
218 </h3>
219
220 @if(!string.IsNullOrWhiteSpace(productNumber))
221 {
222 <p class="products-module__product-article-number">@productNumber</p>
223 }
224
225 @*
226 @if (productCommentCount > 0)
227 {
228 <div class="products-module__product-review-indicator">
229 @renderReviewIndicator("gold", productRating, "row", true, productCommentCount)
230 </div>
231 }
232 *@
233
234 @if (displayPrice && displayProductPrice)
235 {
236 <div class="products-module__product-price-container">
237 @if (hasDiscount)
238 {
239 <span class="products-module__product-price-original">@OriginalPrice</span>
240 <span class="products-module__product-price">@Price</span>
241 }
242 else
243 {
244 <span class="products-module__product-price">@OriginalPrice</span>
245 }
246 <span class="products-module__product-price-suffix">@ProductdetailPriceSuffix</span>
247 @if (!string.IsNullOrWhiteSpace(retailPrice))
248 {
249 <p class="products-module__product-retail-price">
250 @String.Format(Translate("ProductBlockTitle.RetailPrice", "Retail price: {0}"), retailPrice)
251 </p>
252 }
253 @if (hasDiscount)
254 {
255 <p class="products-module__product-your-discount">@Translate("Productdetail.YourProfitLabel", "Uw voordeel:") @yourDiscount</p>
256 }
257 </div>
258 }
259
260 <section class="products-module__product-actions">
261 @if (enableProductStock && !string.IsNullOrWhiteSpace(stockFormat))
262 {
263 if(stockFormat == "text") {
264 if (!string.IsNullOrWhiteSpace(stockText))
265 {
266 <p class="products-module__product-stock-state @stockClass">@string.Format(stockText, stockSize)</p>
267 }
268 }
269 else
270 {
271 string translationTag = "";
272 if(neverOutOfStock)
273 {
274 translationTag = Translate("ProductBlockStockInfo.AmountInStock", "In stock");
275 }
276 else if(stockSize == 1)
277 {
278 translationTag = Translate("ProductBlockStockInfo.AmountInStockSingle", "{0} product in stock");
279 }
280 else if(stockSize > 1)
281 {
282 translationTag = Translate("ProductBlockStockInfo.AmountInStockMultiple", "{0} products in stock");
283 }
284 else if(!isInStock)
285 {
286 translationTag = Translate("ProductBlockStockInfo.AmountOutOfStock", "Out of stock");
287 }
288 <p class="products-module__product-stock-state @stockClass">@string.Format(translationTag, stockSizeFormatted)</p>
289 }
290 }
291
292 @if(enableShoppingCart && enableProductShoppingCart && !isPriceZero)
293 {
294 <add-to-cart
295 class="app-addtocart"
296 data-prodid="@productId"
297 data-variantid="@productVariantId"
298 data-show-text="False"
299 data-min-quantity="@product.PurchaseMinimumQuantity"
300 data-step="@product.PurchaseQuantityStep"
301 data-list-id="@listId"
302 data-list-name="@listName">
303 </add-to-cart>
304 }
305 else
306 {
307 <button class="products-module__more-infomation">@Translate("ProductsModule.MoreInformation", "More information")</button>
308 }
309 </section>
310
311 <a href="@productURL" class="products-module__link" data-id="@productId" data-variantid="@productVariantId" data-number="@productNumber" data-name='@productName.Replace("''", "\\\"").Replace("'", "")' data-position="@index" data-brand='@gtmBrand' data-category='@product.PrimaryOrDefaultGroup.Name.Replace("''", "\\\"").Replace("'", "")' data-listid="@listId" data-listname="@listName" data-gtmprice="@gtmPrice" data-gtmdiscount="@gtmDiscount" data-gtmvalue="@gtmValue" data-currencycode="@Dynamicweb.Ecommerce.Common.Context.Currency.Code" aria-label="@productName"></a>
312 </div>
313 </li>
314 }
315
316 @helper renderProductListEnhancedEcom(string listId, string listName, IEnumerable<ProductViewModel> products) {
317 var index = 1;
318 <text>
319 <script>
320 if(window.dataLayer) {
321 dataLayer.push({
322 'event': 'view_item_list',
323 'ecommerce': {
324 'item_list_id': '@listId',
325 'item_list_name': '@listName',
326 'items': [
327 @foreach (var product in products) {
328 string pName = product.Name.Replace("''", "\\\"").Replace("'", "");
329 string pGroupName = product.PrimaryOrDefaultGroup?.Name?.Replace("''", "\\\"").Replace("'", "");
330 string pBrand = product.Manufacturer?.Name?.Replace("''", "\\\"").Replace("'", "");
331 <text>
332 {
333 'item_id': '@product.Id',
334 'item_name': '@pName',
335 'item_number': '@product.Number',
336 'discount': @product.Discount.Price,
337 'index': @index,
338 'item_brand': '@pBrand',
339 'item_category': '@pGroupName',
340 'item_list_id': '@listId',
341 'item_list_name': '@listName',
342 'item_variant': '@product.VariantId',
343 'price': @product.Price.Price,
344 'quantity': 1,
345 },
346 </text>
347 index++;
348 }
349 ]
350 }
351 });
352 }
353 </script>
354 </text>
355 }
356