PageSourceSearch

https://www.garnelio.de/custom/plugins/DIScoGA4S5/Resources/js/ga4…/datalayer.helper.js?six_jsfix=20260923

js garnelio.de collected 2026-10-02 11:02:07 UTC 50,537 bytes, 1,481 lines download raw bytes

1import CheckoutAccessHelper from "./checkout-access.helper.js?six_jsfix=20260923";
2import ItemListAccessHelper from "./item-list-access.helper.js";
3import ProductAccessHelper from "./product-access.helper.js";
4import StorageAccessHelper from "./storage-access.helper.js";
5import PayloadFormatHelper from './payload-format.helper.js';
6
7export default class DatalayerHelper {
8
9    static login() {
10        const {
11            acceptedMads,
12        } = window;
13        let pushArray = {
14            event: 'login',
15            method: 'mail'
16        };
17        if (acceptedMads) {
18            dataLayer.push({microsoft_ads_object: null});
19            pushArray['microsoft_ads_object'] = {
20                event: 'login',
21                method: 'mail'
22            };
23        }
24        dataLayer.cleanPush(pushArray);
25    }
26
27    static addToCartFromHeader(productId, quantity, remove, allowSave, keepOriginFromStorage) {
28        let pushArray = {event: 'add_to_cart'};
29
30        if (remove) {
31            pushArray['event'] = 'remove_from_cart';
32            allowSave = false;
33        }
34
35        let totalUAValue = parseFloat(ProductAccessHelper.getUAValueFromHeader(productId, quantity));
36        let totalValue = parseFloat(ProductAccessHelper.getValueFromHeader(productId, quantity,false));
37        let uaItem = ProductAccessHelper.getFormUAItemFromHeader(productId);
38
39        const {
40            ga4AdvancedConsentMode,
41            acceptedGa,
42            googleAnalyticsEnabled,
43            ga4Currency,
44            ga4Product,
45            acceptedGads,
46            googleAdsEnabled,
47            ecomm_pagetype,
48            acceptedMeta,
49            acceptedMads,
50            acceptedPinterest,
51            acceptedTiktok
52        } = window;
53
54        let productArray;
55
56        if (ga4Product && ga4Product[productId]) {
57            let {index, item_list_id, item_list_name} = ga4Product[productId];
58
59            productArray = ProductAccessHelper.getProductFromHeader(productId, quantity, index, item_list_id, item_list_name, allowSave, keepOriginFromStorage);
60            StorageAccessHelper.setJsonEntry("ga4item_", productId, productArray);
61            StorageAccessHelper.setEntriesIfMissing([
62                {
63                    entryString: 'item_startPrice_',
64                    productId: productId,
65                    value: ga4Product[productId]["extra"]["item_startPrice"]
66                },
67                {
68                    entryString: 'taxRate_',
69                    productId: productId,
70                    value: ga4Product[productId]["extra"]["taxes"]},
71                {
72                    entryString: 'productId_',
73                    productId: ga4Product[productId]["extra"]['item_shop_id'],
74                    value: productId
75                },
76                {
77                    entryString: 'SKU_',
78                    productId: productId,
79                    value: ga4Product[productId]["extra"]['item_shop_id']
80                },
81            ]);
82        }
83        if ((productArray = StorageAccessHelper.getJsonEntry('ga4item_', productId)) !== null) {
84            productArray['quantity'] = quantity;
85            productArray['discount'] = Math.round((productArray['discount']) * 100) / 100;
86        }
87
88        if ((ga4AdvancedConsentMode || acceptedGa) && googleAnalyticsEnabled) {
89            dataLayer.push({ecommerce: null});
90
91
92            pushArray['ecommerce'] = {
93                currency: ga4Currency,
94                value: parseFloat(totalValue.toFixed(2)),
95                items: [productArray]
96            };
97        }
98
99
100        if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled) {
101            dataLayer.push({items: null});
102
103            pushArray['value'] = parseFloat(totalUAValue.toFixed(2));
104            pushArray['items'] = [uaItem];
105        }
106
107        if (acceptedMeta) {
108            dataLayer.push({meta_object: null});
109
110            let metaItem = ProductAccessHelper.getMetaItemFromItem(productArray);
111
112            pushArray['meta_object'] = {
113                meta_event: remove ? 'RemoveFromCart' : 'AddToCart',
114                meta_object_data: {
115                    contents: [metaItem.contents],
116                    content_type: 'product',
117                    content_name: metaItem.name,
118                    content_category: metaItem.category
119                },
120            };
121        }
122
123        if (acceptedMads) {
124            dataLayer.push({microsoft_ads_object: null});
125            let madsItem = ProductAccessHelper.getMadsItemFromItem(productArray);
126            if (madsItem) {
127                pushArray['microsoft_ads_object'] = {
128                    'event': remove ? 'remove_from_cart' : 'add_to_cart',
129                    'ecomm_prodid': madsItem.prodId,
130                    'ecomm_pagetype': ecomm_pagetype,
131                    'ecomm_totalvalue': parseFloat(madsItem.totalvalue.toFixed(2)),
132                    'revenue_value': parseFloat(totalUAValue.toFixed(2)),
133                    'currency': ga4Currency,
134                    'items': madsItem.lineItem
135                };
136            } else {
137                pushArray['microsoft_ads_object'] = {
138                    'event': remove ? 'remove_from_cart' : 'add_to_cart',
139                    'ecomm_prodid': productId,
140                    'ecomm_pagetype': ecomm_pagetype,
141                    'ecomm_totalvalue': parseFloat(totalValue.toFixed(2)),
142                    'revenue_value': parseFloat(totalUAValue.toFixed(2)),
143                    'currency': ga4Currency,
144                    'items': undefined
145                };
146            }
147        }
148
149        if (acceptedPinterest) {
150            dataLayer.push({pinterest_object: null});
151            let pinterestItem = ProductAccessHelper.getPinterestItemFromItem(productArray);
152            if (pinterestItem) {
153                pushArray['pinterest_object'] = {
154                    pinterest_event: remove ? 'removefromcart' : 'addtocart',
155                    currency: ga4Currency,
156                    line_items: [pinterestItem]
157                };
158            } else {
159                pushArray['pinterest_object'] = {
160                    pinterest_event: 'addtocart',
161                    currency: ga4Currency,
162                    line_items: undefined
163                };
164            }
165        }
166
167        if (acceptedTiktok) {
168            dataLayer.push({tiktok_object: null});
169            let tiktokItem = ProductAccessHelper.getTikTokItemFromItem(productArray);
170            if (tiktokItem) {
171                pushArray['tiktok_object'] = {
172                    tiktok_event: 'AddToCart',
173                    currency: ga4Currency,
174                    value: parseFloat(tiktokItem.totalvalue.toFixed(2)),
175                    quantity: tiktokItem.quantity,
176                    content_type: 'product',
177                    contents: [tiktokItem.lineItem]
178                };
179            } else {
180                pushArray['tiktok_object'] = {
181                    tiktok_event: 'AddToCart',
182                    currency: ga4Currency,
183                    value: undefined,
184                    quantity: undefined,
185                    content_type: 'product',
186                    line_items: undefined
187                };
188            }
189        }
190
191        dataLayer.cleanPush(pushArray);
192    }
193
194    static viewItemList(source, cms) {
195        const {
196            ga4activeNavigationId,
197            searchTerm,
198            ga4AdvancedConsentMode,
199            acceptedGa,
200            googleAnalyticsEnabled,
201            acceptedGads,
202            googleAdsEnabled,
203            acceptedMeta,
204            acceptedMads,
205            searchResult,
206            ga4Currency,
207            ecomm_pagetype,
208            acceptedPinterest
209        } = window;
210
211        let itemsListContainer;
212        let itemListId;
213        let itemListName;
214
215        if (source === 'category') {
216            itemsListContainer = document.querySelector('.listing--container');
217            itemListId = ga4activeNavigationId ? ga4activeNavigationId : '';
218            itemListName = document.title;
219        } else if (source === 'search') {
220            itemsListContainer = document.querySelector('.listing--container');
221            itemListId = 'search=' + searchTerm;
222            itemListName = 'search';
223        } else if (source === 'productCrossSelling') {
224            itemsListContainer = cms;
225            itemListId = cms.getAttribute('data-tab-id');
226            itemListName = cms.querySelector('.tab--title').innerText;
227        } else if (source === "lastSeenProducts") {
228            itemsListContainer = cms;
229            itemListId = "lastSeenProducts";
230            itemListName = "lastSeenProducts";
231        } else {
232            itemsListContainer = cms;
233            itemListId = source;
234            itemListName = cms.querySelector(".panel--title").innerText;
235        }
236
237        if (!itemsListContainer) {
238            return;
239        }
240
241        let pushArray = {event: 'view_item_list'};
242
243        let items = ItemListAccessHelper.getItems(itemsListContainer, itemListId, itemListName, false);
244
245        if ((ga4AdvancedConsentMode || acceptedGa) && googleAnalyticsEnabled) {
246            dataLayer.push({ecommerce: null});
247            pushArray['ecommerce'] = {
248                item_list_id: itemListId,
249                item_list_name: itemListName,
250                items: items
251            };
252        }
253
254        let adsItemsList;
255        let totalValue = 0;
256
257        adsItemsList = ItemListAccessHelper.getItems(itemsListContainer, itemListId, itemListName, true);
258        if (adsItemsList) {
259            totalValue = adsItemsList.pop();
260            if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled) {
261                dataLayer.push({items: null});
262                pushArray['value'] = totalValue;
263                pushArray['items'] = adsItemsList;
264            }
265        }
266
267        if (source === 'search') {
268            this.viewSearchResults(adsItemsList, totalValue);
269        }
270
271        if (source === 'search' && acceptedMeta) {
272            dataLayer.push({meta_object: null});
273
274            let metaItems = searchResult ? ProductAccessHelper.getMetaItemsFromWindow('view_search_results') : undefined;
275
276            pushArray['meta_object'] = {
277                meta_event: 'Search',
278                meta_object_data: {
279                    contents: metaItems ? [metaItems.contents] : undefined,
280                    content_type: 'product',
281                    search_string: searchTerm
282                }
283            };
284        }
285
286        if (acceptedMads) {
287            dataLayer.push({microsoft_ads_object: null});
288            let madsItemsFromItems = ProductAccessHelper.getMadsItemsFromItems(items);
289            if (madsItemsFromItems) {
290                pushArray['microsoft_ads_object'] = {
291                    'event': 'view_item_list',
292                    'ecomm_category': document.title,
293                    'ecomm_prodid': madsItemsFromItems.prodIds,
294                    'ecomm_pagetype': window.ecomm_pagetype,
295                    'ecomm_totalvalue': parseFloat(madsItemsFromItems.totalvalue.toFixed(2)),
296                    'revenue_value': parseFloat(madsItemsFromItems.totalvalue.toFixed(2)),
297                    'currency': ga4Currency,
298                    'items': madsItemsFromItems.lineItems
299                };
300            } else {
301                pushArray['microsoft_ads_object'] = {
302                    'event': 'view_item_list',
303                    'ecomm_category': document.title,
304                    'ecomm_prodid': [],
305                    'ecomm_pagetype': window.ecomm_pagetype,
306                    'ecomm_totalvalue': undefined,
307                    'revenue_value': undefined,
308                    'currency': ga4Currency,
309                    'items': []
310                };
311            }
312        }
313
314
315        dataLayer.cleanPush(pushArray);
316
317        if (acceptedPinterest && source === 'category') {
318            let pushArray = {event: 'view_category'};
319            dataLayer.push({pinterest_object: null, microsoft_ads_object: null, meta_object: null, ecommerce: null});
320            let pinterestItems = ProductAccessHelper.getPinterestItemsFromItems(items);
321            if (pinterestItems) {
322                pushArray['pinterest_object'] = {
323                    pinterest_event: 'viewcategory',
324                    currency: ga4Currency,
325                    line_items: pinterestItems.lineItems
326                };
327            } else {
328                pushArray['pinterest_object'] = {
329                    pinterest_event: 'viewcategory',
330                    currency: ga4Currency,
331                    line_items: undefined
332                };
333            }
334            dataLayer.cleanPush(pushArray);
335        }
336
337    }
338
339    static viewItemFromHeader(productId, quantity) {
340        if (!productId || !(productId in window.ga4Product)) {
341            return;
342        }
343
344        const {
345            ga4Product,
346            ga4Currency,
347            ga4AdvancedConsentMode,
348            acceptedGa,
349            googleAnalyticsEnabled,
350            googleAdsEnabled,
351            acceptedGads,
352            acceptedMeta,
353            acceptedMads,
354            ecomm_pagetype,
355            acceptedPinterest,
356            acceptedTiktok
357        } = window;
358
359        if (!(productId in ga4Product)) {
360            return;
361        }
362
363        let uaValue = ProductAccessHelper.getUAValueFromHeader(productId, quantity);
364        let value = ProductAccessHelper.getValueFromHeader(productId, quantity);
365
366        ga4Product[productId]['index'] = 0;
367        ga4Product[productId]['item_list_id'] = 'product';
368        ga4Product[productId]['item_list_name'] = 'product';
369
370        let pushArray = {event: 'view_item'};
371
372        let productArray = ProductAccessHelper.getProductFromHeader(productId, quantity, 0, "", "", false);
373
374
375        if ((ga4AdvancedConsentMode || acceptedGa) && googleAnalyticsEnabled) {
376            dataLayer.push({ecommerce: null});
377            pushArray['ecommerce'] = {
378                value: value,
379                currency: ga4Currency,
380                items: [productArray]
381            };
382        }
383        if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled) {
384            dataLayer.push({items: null});
385
386            pushArray['value'] = uaValue;
387
388            pushArray['items'] = [ProductAccessHelper.getFormUAItemFromHeader(productId)];
389        }
390
391        if (acceptedMeta) {
392            dataLayer.push({meta_object: null});
393            let metaItem = ProductAccessHelper.getMetaItemFromItem(productArray);
394
395            pushArray['meta_object'] = {
396                meta_event: 'ViewContent',
397                meta_object_data: {
398                    contents: [metaItem.contents],
399                    content_type: 'product',
400                    content_name: metaItem.name,
401                    content_category: metaItem.category
402                },
403            };
404
405        }
406
407        if (acceptedMads) {
408            dataLayer.push({microsoft_ads_object: null});
409            let madsItem = ProductAccessHelper.getMadsItemFromItem(productArray);
410            if (madsItem) {
411                pushArray['microsoft_ads_object'] = {
412                    event: 'view_item',
413                    ecomm_prodid: madsItem.prodId,
414                    ecomm_pagetype: ecomm_pagetype,
415                    ecomm_totalvalue: parseFloat(madsItem.totalvalue.toFixed(2)),
416                    revenue_value: parseFloat(madsItem.totalvalue.toFixed(2)),
417                    currency: ga4Currency,
418                    items: madsItem.lineItem
419                };
420            } else {
421                pushArray['microsoft_ads_object'] = {
422                    event: 'view_item',
423                    ecomm_prodid: productId,
424                    ecomm_pagetype: ecomm_pagetype,
425                    ecomm_totalvalue: parseFloat(value.toFixed(2)),
426                    revenue_value: parseFloat(value.toFixed(2)),
427                    currency: ga4Currency,
428                    items: undefined
429                };
430            }
431        }
432
433        if (acceptedPinterest) {
434            dataLayer.push({pinterest_object: null});
435            let pinterestItem = ProductAccessHelper.getPinterestItemFromItem(productArray);
436            if (pinterestItem) {
437                pushArray['pinterest_object'] = {
438                    pinterest_event: 'pagevisit',
439                    currency: ga4Currency,
440                    line_items: [pinterestItem]
441                };
442            } else {
443                pushArray['pinterest_object'] = {
444                    pinterest_event: 'pagevisit',
445                    currency: ga4Currency,
446                    line_items: undefined
447                };
448            }
449
450        }
451
452        if (acceptedTiktok) {
453            dataLayer.push({tiktok_object: null});
454            let tiktokItem = ProductAccessHelper.getTikTokItemFromItem(productArray);
455            if (tiktokItem) {
456                pushArray['tiktok_object'] = {
457                    tiktok_event: 'ViewContent',
458                    currency: ga4Currency,
459                    value: parseFloat(tiktokItem.totalvalue.toFixed(2)),
460                    content_type: 'product',
461                    contents: [tiktokItem.lineItem]
462                };
463            } else {
464                pushArray['tiktok_object'] = {
465                    tiktok_event: 'ViewContent',
466                    currency: ga4Currency,
467                    value: undefined,
468                    content_type: 'product',
469                    line_items: undefined
470                };
471            }
472        }
473
474        StorageAccessHelper.setJsonEntry('ga4item_', productId, productArray);
475
476        dataLayer.cleanPush(pushArray);
477
478    }
479
480    static selectItem(item, itemListId, itemListName) {
481        if (!item) {
482            return;
483        }
484
485        const {
486            ga4Currency,
487            acceptedMads,
488            ecomm_pagetype
489        } = window;
490
491        dataLayer.push({ecommerce: null, value: null, items: null, meta_object: null, microsoft_ads_object: null});
492
493        let pushArray = {event: 'select_item'};
494
495        pushArray['ecommerce'] = {
496            item_list_id: itemListId,
497            item_list_name: itemListName,
498            items: item
499        };
500
501        if (acceptedMads) {
502            let madsItem = ProductAccessHelper.getMadsItemFromItem(item);
503            if (madsItem) {
504                pushArray['microsoft_ads_object'] = {
505                    'event': 'select_content',
506                    'ecomm_prodid': madsItem.prodId,
507                    'ecomm_pagetype': ecomm_pagetype,
508                    'ecomm_totalvalue': parseFloat(madsItem.totalvalue.toFixed(2)),
509                    'revenue_value': parseFloat(madsItem.totalvalue.toFixed(2)),
510                    'currency': ga4Currency,
511                    'items': madsItem.lineItem
512                };
513            } else {
514                pushArray['microsoft_ads_object'] = {
515                    'event': 'select_content',
516                    'ecomm_prodid': undefined,
517                    'ecomm_pagetype': ecomm_pagetype,
518                    'ecomm_totalvalue': undefined,
519                    'revenue_value': undefined,
520                    'currency': ga4Currency,
521                    'items': undefined
522                };
523            }
524        }
525
526        dataLayer.cleanPush(pushArray);
527    }
528
529    static addToCartFromForm(item) {
530
531        let pushArray = {event: 'add_to_cart'};
532
533        if (!item) {
534            return;
535        }
536
537        const {
538            ga4Currency,
539            acceptedMeta
540        } = window;
541
542        dataLayer.push({ecommerce: null, value: null, items: null});
543
544        pushArray['ecommerce'] = {
545            currency: ga4Currency,
546            items: [item]
547        };
548
549        if (acceptedMeta) {
550            dataLayer.push({meta_object: null});
551
552            pushArray['meta_object'] = {
553                meta_event: 'AddToCart',
554                meta_object_data: {
555                    contents: [{
556                        id: item.item_id,
557                        item_price: undefined
558                    }],
559                    content_type: 'product',
560                    content_name: undefined,
561                    content_category: undefined
562                },
563            };
564
565        }
566
567        dataLayer.cleanPush(pushArray);
568    }
569
570    static addToWishlist(item, valueString) {
571
572        if (!item) {
573            return;
574        }
575
576        let pushArray = {event: 'add_to_wishlist'};
577
578        const {
579            ga4Currency,
580            acceptedMeta,
581            acceptedMads,
582            ecomm_pagetype,
583            acceptedTiktok
584        } = window;
585
586        dataLayer.push({ecommerce: null, value: null, items: null});
587
588        const value = parseFloat(valueString.toFixed(2))
589
590        pushArray['ecommerce'] = {
591            currency: ga4Currency,
592            value: value,
593            items: [item]
594        };
595
596        if (acceptedMeta) {
597            dataLayer.push({meta_object: null});
598            let metaItem = ProductAccessHelper.getMetaItemFromItem(item);
599
600            pushArray['meta_object'] = {
601                meta_event: 'AddToWishlist',
602                meta_object_data: {
603                    contents: [metaItem.contents],
604                    content_type: 'product',
605                    content_name: metaItem.name,
606                    content_category: metaItem.category
607                },
608            };
609        }
610
611        if (acceptedMads) {
612            dataLayer.push({microsoft_ads_object: null});
613            let madsItem = ProductAccessHelper.getMadsItemFromItem(item);
614            pushArray['microsoft_ads_object'] = {
615                'event': 'add_to_wishlist',
616                'ecomm_prodid': madsItem.prodId,
617                'ecomm_pagetype': ecomm_pagetype,
618                'ecomm_totalvalue': value,
619                'revenue_value': value,
620                'currency': ga4Currency,
621                'items': madsItem.lineItem
622            };
623        }
624
625        if (acceptedTiktok) {
626            dataLayer.push({tiktok_object: null});
627            let tiktokItem = ProductAccessHelper.getTikTokItemFromItem(item);
628            if (tiktokItem) {
629                pushArray['tiktok_object'] = {
630                    tiktok_event: 'AddToWishlist',
631                    currency: ga4Currency,
632                    value: parseFloat(tiktokItem.totalvalue.toFixed(2)),
633                    content_type: 'product',
634                    contents: [tiktokItem.lineItem]
635                };
636            } else {
637                pushArray['tiktok_object'] = {
638                    tiktok_event: 'AddToWishlist',
639                    currency: ga4Currency,
640                    value: undefined,
641                    content_type: 'product',
642                    line_items: undefined
643                };
644            }
645        }
646        dataLayer.cleanPush(pushArray);
647    }
648
649    static shippingInfo(checkoutContainer, shipping) {
650        if (!checkoutContainer || !shipping) {
651            return;
652        }
653
654        const {
655            ga4Currency
656        } = window;
657
658        dataLayer.push({ecommerce
658: null, value: null, items: null});
659
660        dataLayer.push({
661            event: 'add_shipping_info',
662            ecommerce: {
663                currency: ga4Currency,
664                value: parseFloat(checkoutContainer.dataset.value.replace(",", ".")),
665                coupon: CheckoutAccessHelper.getCoupon(checkoutContainer).coupon,
666                shipping_tier: shipping.toString(),
667                items: CheckoutAccessHelper.getItemsFromStorage(checkoutContainer)
668            }
669        });
670    }
671
672    static paymentInfo(checkoutContainer, payment) {
673        if (!checkoutContainer || !payment) {
674            return;
675        }
676
677        const {
678            ga4Currency,
679            acceptedMeta,
680            acceptedMads,
681            ecomm_pagetype,
682            acceptedTiktok
683        } = window;
684
685        dataLayer.push({ecommerce: null, value: null, items: null});
686
687        let pushArray = {event: 'add_payment_info'};
688        let items = CheckoutAccessHelper.getItemsFromStorage(checkoutContainer)
689        let value = parseFloat(checkoutContainer.dataset.value.replace(",", "."));
690
691        pushArray['ecommerce'] = {
692            currency: ga4Currency,
693            value: value,
694            coupon: CheckoutAccessHelper.getCoupon(checkoutContainer).coupon,
695            payment_type: payment.toString(),
696            items: items
697        };
698
699        if (acceptedMeta) {
700            dataLayer.push({meta_object: null});
701
702            pushArray['meta_object'] = {
703                meta_event: 'AddPaymentInfo'
704            };
705        }
706
707        if (acceptedMads) {
708            dataLayer.push({microsoft_ads_object: null});
709            let madsItems = ProductAccessHelper.getMadsItemsFromItems(items)
710            if (madsItems && madsItems.prodIds.length > 0) {
711                pushArray['microsoft_ads_object'] = {
712                    'event': 'add_payment_info',
713                    'ecomm_prodid': madsItems.prodIds,
714                    'ecomm_pagetype': ecomm_pagetype
715                };
716            } else {
717                pushArray['microsoft_ads_object'] = {
718                    'event': 'add_payment_info',
719                    'ecomm_prodid': undefined,
720                    'ecomm_pagetype': ecomm_pagetype
721                }
722            }
723        }
724
725        if (acceptedTiktok) {
726            dataLayer.push({tiktok_object: null});
727            let tiktokItems = ProductAccessHelper.getTikTokItemsFromItems(items);
728            if (tiktokItems) {
729                pushArray['tiktok_object'] = {
730                    tiktok_event: 'AddPaymentInfo',
731                    currency: ga4Currency,
732                    value: parseFloat(tiktokItems.totalvalue.toFixed(2)),
733                    content_type: 'product',
734                    contents: tiktokItems.lineItems
735                };
736            } else {
737                pushArray['tiktok_object'] = {
738                    tiktok_event: 'AddPaymentInfo',
739                    currency: ga4Currency,
740                    value: value,
741                    content_type: 'product',
742                    contents: undefined
743                }
744            }
745        }
746
747        dataLayer.cleanPush(pushArray);
748
749    }
750
751    static async purchase(checkoutContainer, adsContainer, transactionId) {
752        let pushArray = {event: 'purchase'};
753
754        const {
755            ga4Currency,
756            ga4AdvancedConsentMode,
757            acceptedGa,
758            googleAnalyticsEnabled,
759            acceptedGads,
760            googleAdsEnabled,
761            ga4orderNumber,
762            ecomm_pagetype,
763            acceptedMeta,
764            acceptedMads,
765            acceptedPinterest,
766            acceptedTiktok
767        } = window;
768
769        const email = adsContainer.dataset.useremail;
770        const salutation = adsContainer.dataset.salutation;
771        let gender = 'not_specified';
772        if (salutation === 'mr') {
773            gender = 'male';
774        } else if (salutation === 'mrs') {
775            gender = 'female';
776        }
777        const sha256_email = await this.sha256(email);
778        const first_name = adsContainer.dataset.firstname;
779        const sha256_first_name = await this.sha256(first_name)
780        const last_name = adsContainer.dataset.lastname;
781        const sha256_last_name = await this.sha256(last_name);
782        const street = adsContainer.dataset.street;
783        const city = adsContainer.dataset.city;
784        const postal_code = adsContainer.dataset.zip;
785        const region = adsContainer.dataset.region;
786        const country = adsContainer.dataset.land;
787        const phone_number = adsContainer.dataset.phone ? adsContainer.dataset.phone : null;
788        const sha256_phone_number = phone_number ? await this.sha256(phone_number): null;
789        const e164_phone_number = phone_number ? PayloadFormatHelper.gete164Phone(phone_number, country) : null;
790        const sha256_e164_phone_number = e164_phone_number ? await this.sha256(e164_phone_number): null;
791        const phone_number_international = phone_number ? PayloadFormatHelper.geteItnlPhone(phone_number, country) : null;
792        const sha256_phone_number_international = e164_phone_number ? await this.sha256(e164_phone_number) : null;
793        const transaction_id = ga4orderNumber.toString();
794        const sha256_transaction_id = await DatalayerHelper.sha256(transaction_id);
795
796        const adsValue = this.getTotalAdsValue(
797            checkoutContainer.dataset.value, checkoutContainer.dataset.tax, checkoutContainer.dataset.shipping
798        )
799
800        const discount = CheckoutAccessHelper.getCoupon(checkoutContainer).discount;
801
802        const coupon_code = CheckoutAccessHelper.getCoupon(checkoutContainer).code;
803
804        let ecommerce = this.checkoutContent(checkoutContainer, transactionId);
805
806
807        if ((ga4AdvancedConsentMode || acceptedGa) && googleAnalyticsEnabled && checkoutContainer) {
808            dataLayer.push({ecommerce: null});
809            pushArray['ecommerce'] = ecommerce;
810            pushArray['coupon_code'] = coupon_code;
811        }
812
813        if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled && adsContainer) {
814            pushArray['value'] = parseFloat(adsValue.toFixed(2));
815            pushArray['transaction_id'] = transaction_id;
816            pushArray['currency'] = ga4Currency;
817            pushArray['discount'] = discount;
818
819
820            dataLayer.push({items: null});
821            pushArray['items'] = CheckoutAccessHelper.getAdsItemsFromStorage();
822
823
824            pushArray['email'] = sha256_email;
825
826            if(sha256_e164_phone_number) pushArray['phone_number'] = sha256_e164_phone_number;
827
828            let address = {};
829            address['first_name'] = sha256_first_name;
830            address['last_name'] = sha256_last_name;
831            address['street'] = street;
832            address['city'] = city;
833            address['region'] = region;
834            address['postal_code'] = postal_code;
835            address['country'] = country;
836            pushArray['address'] = address;
837
838        }
839
840        if (acceptedMeta) {
841            dataLayer.push({meta_object: null});
842            let metaItems = ProductAccessHelper.getMetaItemsFromItems(ecommerce.items);
843
844            pushArray['meta_object'] = {
845                meta_event: 'Purchase',
846                meta_object_data: {
847                    value: adsValue ? parseFloat(adsValue.toFixed(2)) : ecommerce.value,
848                    currency: ga4Currency,
849                    contents: metaItems.contents,
850                    content_type: 'product',
851                    num_items: metaItems.numberOfItems,
852                    order_id: transaction_id
853                },
854            };
855        }
856
857        if (acceptedMads) {
858            dataLayer.push({microsoft_ads_object: null});
859            let madsItems = ProductAccessHelper.getMadsItemsFromItems(ecommerce.items);
860            pushArray['microsoft_ads_object'] = {
861                event: 'purchase',
862                transaction_id: transaction_id,
863                ecomm_prodid: madsItems ? madsItems.prodIds : undefined,
864                ecomm_pagetype: window.ecomm_pagetype,
865                ecomm_totalvalue: madsItems ? parseFloat(madsItems.totalvalue.toFixed(2)) : ecommerce.value,
866                revenue_value: adsValue ? parseFloat(adsValue.toFixed(2)) : ecommerce.value,
867                currency: ga4Currency,
868                tax: ecommerce.tax,
869                items: madsItems ? madsItems.lineItems : undefined
870            };
871        }
872
873        if (acceptedPinterest) {
874            dataLayer.push({pinterest_object: null});
875            let pinterestItems = ProductAccessHelper.getPinterestItemsFromItems(ecommerce.items);
876            pushArray['pinterest_object'] = {
877                pinterest_event: 'checkout',
878                value: adsValue ? adsValue : ecommerce.value,
879                order_quantity: pinterestItems ? pinterestItems.numberOfItems : undefined,
880                currency: ga4Currency,
881                order_id: transaction_id,
882                promo_code: coupon_code,
883                line_items: pinterestItems ? pinterestItems.lineItems : undefined
884            };
885        }
886
887        if (acceptedTiktok) {
888            dataLayer.push({tiktok_object: null});
889            let tiktokItems = ProductAccessHelper.getTikTokItemsFromItems(ecommerce.items);
890            if (tiktokItems) {
891                pushArray['tiktok_object'] = {
892                    tiktok_event: 'CompletePayment',
893                    currency: ga4Currency,
894                    quantity: tiktokItems.numberOfItems,
895                    value: adsValue ? parseFloat(adsValue.toFixed(2)) : ecommerce.value,
896                    content_type: 'product',
897                    contents: tiktokItems.lineItems
898                };
899            } else {
900                pushArray['tiktok_object'] = {
901                    tiktok_event: 'CompletePayment',
902                    currency: ga4Currency,
903                    quantity: undefined,
904                    value: adsValue ? parseFloat(adsValue.toFixed(2)) : ecommerce.value,
905                    content_type: 'product',
906                    contents: undefined
907                }
908            }
909        }
910
911        if(sha256_e164_phone_number) {
912            pushArray['additional'] = {
913                email,
914                sha256_email,
915                first_name,
916                sha256_first_name,
917                last_name,
918                sha256_last_name,
919                e164_phone_number,
920                sha256_e164_phone_number,
921                phone_number,
922                sha256_phone_number,
923                phone_number_international,
924                sha256_phone_number_international,
925                gender,
926                street,
927                city,
928                postal_code,
929                region,
930                country,
931                transaction_id,
932                sha256_transaction_id
933            };
934        }else {
935            pushArray['additional'] = {
936                email,
937                sha256_email,
938                first_name,
939                sha256_first_name,
940                last_name,
941                sha256_last_name,
942                gender,
943                street,
944                city,
945                postal_code,
946                region,
947                country,
948                transaction_id,
949                sha256_transaction_id
950            };
951        }
952
953
954        dataLayer.cleanPush(pushArray);
955    }
956
957    static viewCart(checkoutContainer) {
958        dataLayer.push({ecommerce: null, value: null, items: null});
959        dataLayer.cleanPush({
960            event: 'view_cart',
961            ecommerce: this.cartContent(checkoutContainer),
962            coupon_code: CheckoutAccessHelper.getCoupon(checkoutContainer).code
963        });
964    }
965
966    static beginCheckout(checkoutContainer) {
967        let pushArray = {event: 'begin_checkout'};
968
969        const {
970            ga4Currency,
971            ecomm_pagetype,
972            acceptedMeta,
973            acceptedMads,
974            acceptedTiktok
975        } = window;
976
977        dataLayer.push({ecommerce: null, value: null, items: null});
978
979        const currency = ga4Currency;
980        const value = parseFloat(checkoutContainer.dataset.value.replace(",", "."));
981
982        const items = CheckoutAccessHelper.getItemsFromStorage(checkoutContainer);
983        const adsValue = this.getTotalAdsValue(
984            checkoutContainer.dataset.value, checkoutContainer.dataset.tax, checkoutContainer.dataset.shipping
985        )
986
987        pushArray['ecommerce'] = {
988            currency,
989            value,
990            coupon: CheckoutAccessHelper.getCoupon(checkoutContainer).coupon,
991            items
992        };
993
994        if (acceptedMeta) {
995            dataLayer.push({meta_object: null});
996
997            let metaItems = ProductAccessHelper.getMetaItemsFromItems(items);
998
999
1000            pushArray['meta_object'] = {
1001                meta_event: 'InitiateCheckout',
1002                meta_object_data: {
1003                    contents: [metaItems.contents],
1004                    content_type: 'product',
1005                    num_items: metaItems.numberOfItems,
1006                },
1007            };
1008        }
1009
1010        if (acceptedMads) {
1011            dataLayer.push({microsoft_ads_object: null});
1012            let madsItems = ProductAccessHelper.getMadsItemsFromItems(items);
1013            pushArray['microsoft_ads_object'] = {
1014                event: 'begin_checkout',
1015                ecomm_prodid: madsItems ? madsItems.prodIds : undefined,
1016                ecomm_pagetype: ecomm_pagetype,
1017                ecomm_totalvalue: madsItems ? parseFloat(madsItems.totalvalue.toFixed(2)) : value,
1018                revenue_value: adsValue ? parseFloat(adsValue.toFixed(2)) : value,
1019                currency,
1020                items: madsItems ? madsItems.lineItems : undefined
1021            };
1022        }
1023
1024        if (acceptedTiktok) {
1025            dataLayer.push({tiktok_object: null});
1026            let tiktokItems = ProductAccessHelper.getTikTokItemsFromItems(items);
1027            if (tiktokItems) {
1028                pushArray['tiktok_object'] = {
1029                    tiktok_event: 'InitiateCheckout',
1030                    currency: ga4Currency,
1031                    value: parseFloat(tiktokItems.totalvalue.toFixed(2)),
1032                    content_type: 'product',
1033                    contents: tiktokItems.lineItems
1034                };
1035            } else {
1036                pushArray['tiktok_object'] = {
1037                    tiktok_event: 'InitiateCheckout',
1038                    currency: ga4Currency,
1039                    value: value,
1040                    content_type: 'product',
1041                    contents: undefined
1042                }
1043            }
1044        }
1045
1046        dataLayer.cleanPush(pushArray);
1047    }
1048
1049    static signUp() {
1050
1051        let pushArray = {
1052            event: 'sign_up',
1053            method: 'mail'
1054        };
1055
1056        const {
1057            acceptedMeta,
1058            acceptedMads,
1059            acceptedPinterest,
1060            acceptedTiktok
1061        } = window;
1062
1063        if (acceptedMeta) {
1064            dataLayer.push({meta_object: null});
1065
1066            pushArray['meta_object'] = {
1067                meta_event: 'CompleteRegistration'
1068            };
1069        }
1070
1071        if (acceptedMads) {
1072            dataLayer.push({microsoft_ads_object: null});
1073            pushArray['microsoft_ads_object'] = {
1074                event: 'sign_up',
1075                method: 'mail'
1076            };
1077        }
1078
1079        if (acceptedPinterest) {
1080            dataLayer.push({pinterest_object: null});
1081            pushArray['pinterest_object'] = {
1082                pinterest_event: 'signup',
1083            };
1084        }
1085
1086        if (acceptedTiktok) {
1087            dataLayer.push({tiktok_object: null});
1088            pushArray['tiktok_object'] = {
1089                tiktok_event: 'CompleteRegistration',
1090            };
1091        }
1092
1093
1094        dataLayer.cleanPush(pushArray);
1095
1096    }
1097
1098    /*
1099       static account(eventName, method) {
1100           const commonAccountData = {event: eventName, method};
1101
1102           if (window.ga4UserId) {
1103               dataLayer.push({...commonAccountData, user_id: window.ga4UserId});
1104
1105               return;
1106           }
1107
1108           dataLayer.push(commonAccountData);
1109       }
1110   */
1111    static viewSearchResults(adsItemsList, totalValue) {
1112
1113        let pushArray = {event: 'view_search_results'};
1114        dataLayer.push({ecommerce: null});
1115
1116        const {
1117            searchTerm,
1118            searchResult,
1119            ga4AdvancedConsentMode,
1120            acceptedGads,
1121            googleAdsEnabled,
1122            acceptedMeta,
1123            acceptedMads,
1124            ecomm_pagetype
1125        } = window;
1126
1127        pushArray['search_term'] = searchTerm;
1128
1129        pushArray['search_result'] = 0;
1130        if (searchResult) {
1131            pushArray['search_result'] = parseInt(searchResult, 10);
1132        }
1133
1134
1135        if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled && totalValue && adsItemsList) {
1136            dataLayer.push({items: null});
1137            pushArray['value'] = totalValue;
1138            pushArray['items'] = adsItemsList;
1139        }
1140
1141        if (acceptedMeta) {
1142            dataLayer.push({meta_object: null});
1143
1144            let metaItems = searchResult ? ProductAccessHelper.getMetaItemsFromWindow('view_search_results') : undefined;
1145
1146            pushArray['meta_object'] = {
1147                meta_event: 'Search',
1148                meta_object_data: {
1149                    contents: metaItems ? [metaItems.contents] : undefined,
1150                    content_type: 'product',
1151                    search_string: searchTerm
1152                }
1153            };
1154        }
1155
1156        if (acceptedMads) {
1157            dataLayer.push({microsoft_ads_object: null});
1158
1159            const {
1160                ga4Product
1161            } = window;
1162
1163            let products = JSON.parse(JSON.stringify(ga4Product));
1164
1165            let madsItemsFromItems = products ? ProductAccessHelper.getMadsItemsFromItems(products) : undefined;
1166
1167            if (madsItemsFromItems) {
1168                pushArray['microsoft_ads_object'] = {
1169                    event: 'view_search_results',
1170                    ecomm_query: searchTerm,
1171                    ecomm_prodid: madsItemsFromItems.prodIds,
1172                    ecomm_pagetype: ecomm_pagetype,
1173                    search_term: searchTerm
1174                };
1175            } else {
1176                pushArray['microsoft_ads_object'] = {
1177                    event: 'view_search_results',
1178                    ecomm_query: searchTerm,
1179                    ecomm_prodid: undefined,
1180                    ecomm_pagetype: ecomm_pagetype,
1181                    search_term: searchTerm,
1182                };
1183            }
1184        }
1185
1186        dataLayer.cleanPush(pushArray);
1187
1188    }
1189
1190    static changeQty(action) {
1191        const select = action.target;
1192
1193
1194        let difference = select.querySelector('[selected="selected"]').value - select.value;
1195
1196        let remove = false;
1197
1198        if (difference > 0) {
1199            remove = true;
1200        }
1201
1202        let shopId = select.closest('.row--product').querySelector('[name="sArticle"]').value;
1203
1204        let productId;
1205
1206        if (shopId) {
1207            let lineItemsContainer = document.getElementById('discoga4-checkout');
1208            if (lineItemsContainer) {
1209                // let itemContainer = lineItemsContainer.querySelector("[data-id=" + lastSegment + "]");
1210                let itemContainer = lineItemsContainer.querySelector('[data-id="' + shopId + '"]');
1211                if (itemContainer) {
1212                    productId = itemContainer.getAttribute("data-sku");
1213                }
1214            }
1215        }
1216
1217        let quantity = Math.abs(difference);
1218
1219        this.addToCartFromHeader(productId, quantity, remove, false, true);
1220    }
1221
1222    static search() {
1223
1224        dataLayer.push({ecommerce: null});
1225
1226        const {
1227            searchResult,
1228            searchTerm,
1229            acceptedMads,
1230            acceptedPinterest
1231        } = window;
1232
1233        let pushArray = {
1234            event: 'search',
1235            search_term: searchTerm ? searchTerm : undefined,
1236            search_result: searchResult ? parseInt(searchResult, 10) : undefined
1237        };
1238
1239        if (acceptedMads) {
1240            dataLayer.push({microsoft_ads_object: null});
1241            pushArray['microsoft_ads_object'] = {
1242                event: 'search',
1243                search_term: searchTerm
1244            };
1245        }
1246
1247        if (acceptedPinterest) {
1248            dataLayer.push({pinterest_object: null});
1249            pushArray['pinterest_object'] = {
1250                pinterest_event: 'search',
1251                search_query: searchTerm
1252            };
1253        }
1254
1255        dataLayer.cleanPush(pushArray);
1256
1257    }
1258
1259    static lead() {
1260        dataLayer.push({ecommerce: null, value: null, items: null});
1261
1262        const {
1263            generateLeadValue,
1264            acceptedMeta,
1265            acceptedMads,
1266            ecomm_pagetype,
1267            ga4Currency,
1268            acceptedPinterest,
1269            acceptedTiktok
1270        } = window;
1271
1272        let value = parseFloat(generateLeadValue);
1273
1274        let pushArray = {
1275            event: 'generate_lead',
1276            currency: ga4Currency,
1277            value: value
1278        };
1279
1280        if (acceptedMeta) {
1281            dataLayer.push({meta_object: null});
1282            pushArray['meta_object'] = {
1283                meta_event: 'Lead',
1284                meta_object_data: {
1285                    value: value,
1286                    currency: ga4Currency
1287                },
1288            };
1289        }
1290
1291        if (acceptedMads) {
1292            dataLayer.push({microsoft_ads_object: null});
1293            pushArray['microsoft_ads_object'] = {
1294                event: 'generate_lead',
1295                ecomm_pagetype: ecomm_pagetype,
1296                ecomm_totalvalue: value,
1297                revenue_value: value,
1298                currency: ga4Currency,
1299            };
1300        }
1301        if (acceptedPinterest) {
1302            dataLayer.push({pinterest_object: null});
1303            pushArray['pinterest_object'] = {
1304                pinterest_event: 'lead',
1305                lead_type: 'Contactform',
1306            };
1307        }
1308
1309        if (acceptedTiktok) {
1310            dataLayer.push({tiktok_object: null});
1311            pushArray['tiktok_object'] = {
1312                tiktok_event: 'SubmitForm',
1313            };
1314        }
1315
1316        dataLayer.cleanPush(pushArray);
1317    }
1318
1319    static forms(eventName) {
1320        dataLayer.push({ecommerce: null, value: null, items: null});
1321        const {
1322            generateLeadValue,
1323            ga4Currency
1324        } = window;
1325        dataLayer.push({
1326            event: eventName,
1327            currency: ga4Currency,
1328            value: generateLeadValue
1329        });
1330    }
1331
1332
1333    static cartContent(checkoutContainer) {
1334        if (checkoutContainer.dataset) {
1335            const {
1336                ga4Currency
1337            } = window;
1338            return {
1339                currency: ga4Currency,
1340                value: parseFloat(checkoutContainer.dataset.value.replace(",", ".")),
1341                items: CheckoutAccessHelper.getItemsFromStorage(c
1341heckoutContainer)
1342            };
1343        }
1344        return null;
1345
1346    };
1347
1348    static checkoutContent(checkoutContainer, transactionId) {
1349
1350        let coupon = CheckoutAccessHelper.getCoupon(checkoutContainer).coupon;
1351        let discount = Math.abs(CheckoutAccessHelper.getCoupon(checkoutContainer).discount);
1352
1353        const {
1354            ga4Currency
1355        } = window;
1356
1357        if (transactionId) {
1358            return {
1359                transaction_id: transactionId,
1360                currency: ga4Currency,
1361                value: parseFloat(checkoutContainer.dataset.value.replace(",", ".")),
1362                shipping: parseFloat(checkoutContainer.dataset.shipping),
1363                tax: parseFloat(checkoutContainer.dataset.tax),
1364                coupon: coupon,
1365                discount: parseFloat(discount.toFixed(2)),
1366                items: CheckoutAccessHelper.getItemsFromStorage(checkoutContainer)
1367            };
1368        }
1369        return {
1370            currency: ga4Currency,
1371            value: parseFloat(checkoutContainer.dataset.value.replace(",", ".")),
1372            shipping: parseFloat(checkoutContainer.dataset.shipping),
1373            tax: parseFloat(checkoutContainer.dataset.tax),
1374            coupon: coupon,
1375            discount: parseFloat(discount.toFixed(2)),
1376            items: CheckoutAccessHelper.getItemsFromStorage(checkoutContainer)
1377        };
1378    };
1379
1380    static async sha256(str) {
1381        const buffer = new TextEncoder("utf-8").encode(str);
1382        const hash = await crypto.subtle.digest("SHA-256", buffer);
1383
1384        return this.hex(hash);
1385    }
1386
1387    static hex(buffer) {
1388        let digest = '';
1389        let view = new DataView(buffer);
1390        for (let i = 0; i < view.byteLength; i += 4) {
1391            let value = view.getUint32(i);
1392            let stringValue = value.toString(16);
1393            let padding = '00000000';
1394            let paddedValue = (padding + stringValue).slice(-padding.length);
1395            digest += paddedValue;
1396        }
1397        return digest;
1398    }
1399
1400    static replaceEmptyStringsWithUndefined(obj) {
1401        if (typeof obj !== 'object' || null === obj) {
1402            return obj;
1403        }
1404
1405        if (Array.isArray(obj)) {
1406            for (let i = 0; i < obj.length; i++) {
1407                if (typeof obj[i] === 'object' && obj[i] !== null) {
1408                    this.replaceEmptyStringsWithUndefined(obj[i]);
1409                } else if (obj[i] === '') {
1410                    obj[i] = undefined;
1411                }
1412            }
1413
1414            return obj;
1415        }
1416
1417        for (const key in obj) {
1418            if (obj.hasOwnProperty(key)) {
1419                const value = obj[key];
1420                if (typeof value === 'object' && value !== null) {
1421                    this.replaceEmptyStringsWithUndefined(value);
1422                } else if (value === '') {
1423                    obj[key] = undefined;
1424                }
1425            }
1426        }
1427
1428        return obj;
1429    }
1430
1431    static getTotalAdsValue(rawValue, tax, shipping) {
1432        let totalAdsValue = parseFloat(rawValue) - parseFloat(shipping);
1433        // BruttoWithoutShipping
1434
1435
1436        const calculatedShipping = this.calculateShipping(shipping, this.getGlobalPurchaseTaxState());
1437        const {
1438            conversionConfiguration
1439        } = window;
1440
1441        switch (conversionConfiguration) {
1442            case ("bruttoWithShipping"): // BruttoWithShipping
1443                totalAdsValue += parseFloat(calculatedShipping);
1444                break;
1445            case ("nettoWithShipping"): // NettoWithShipping
1446                totalAdsValue = totalAdsValue - parseFloat(tax) + parseFloat(calculatedShipping);
1447                break;
1448            case ("netto"): // NettoWithoutShipping
1449                totalAdsValue -= parseFloat(tax);
1450                break;
1451        }
1452
1453        return Math.round(totalAdsValue * 100) / 100;
1454    }
1455
1456    static calculateShipping(shipping, type = 'net') {
1457        let storageShipping = sessionStorage.getItem('ga4_shipping_price');
1458        if (!storageShipping) {
1459            return 0;
1460        }
1461
1462        if (!type) {
1463            return shipping;
1464        }
1465
1466        storageShipping = JSON.parse(storageShipping);
1467
1468        return storageShipping[type];
1469    }
1470
1471    static getGlobalPurchaseTaxState() {
1472        let storageShipping = sessionStorage.getItem('ga4_shipping_price');
1473        if (!storageShipping) {
1474            return 'gross';
1475        }
1476
1477        const {globalTaxState} = JSON.parse(storageShipping);
1478
1479        return globalTaxState;
1480    }
1481}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.