-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtemplate.tpl
More file actions
213 lines (173 loc) · 5.84 KB
/
template.tpl
File metadata and controls
213 lines (173 loc) · 5.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
___TERMS_OF_SERVICE___
By creating or modifying this file you agree to Google Tag Manager's Community
Template Gallery Developer Terms of Service available at
https://developers.google.com/tag-manager/gallery-tos (or such other URL as
Google may provide), as modified from time to time.
___INFO___
{
"type": "MACRO",
"id": "cvt_temp_public_id",
"version": 1,
"securityGroups": [],
"displayName": "dataLayer Picker | Up Blue",
"categories": [
"ANALYTICS",
"UTILITY"
],
"description": "Extracts and transforms ecommerce data from the dataLayer into GA4-compatible format. Zero configuration needed. Built by Up Blue (upblue.pl).",
"containerContexts": [
"WEB"
]
}
___TEMPLATE_PARAMETERS___
[]
___SANDBOXED_JS_FOR_WEB_TEMPLATE___
const copyFromDataLayer = require('copyFromDataLayer');
const queryPermission = require('queryPermission');
// 1. Bezpieczne pobranie nazwy zdarzenia (jeśli mamy uprawnienia)
let eventName = '';
if (queryPermission('read_data_layer', 'event')) {
eventName = copyFromDataLayer('event');
}
// 2. Bezpieczne pobranie obiektu ecommerce lub eventModel
let ecomObj = undefined;
if (queryPermission('read_data_layer', 'ecommerce')) {
ecomObj = copyFromDataLayer('ecommerce');
}
// Fallback do eventModel
if (!ecomObj && queryPermission('read_data_layer', 'eventModel')) {
ecomObj = copyFromDataLayer('eventModel');
}
// Jeśli nigdzie nie ma danych E-commerce, zwracamy undefined
if (!ecomObj) {
return undefined;
}
const items = ecomObj.items || [];
let ga4Obj = {};
// Dodajemy tablicę produktów, jeśli istnieje
if (items.length > 0) {
ga4Obj.items = items;
}
// Podstawowe parametry
if (ecomObj.value !== undefined) ga4Obj.value = ecomObj.value;
if (ecomObj.currency !== undefined) ga4Obj.currency = ecomObj.currency;
if (ecomObj.coupon !== undefined) ga4Obj.coupon = ecomObj.coupon;
// Parametry list (np. dla view_item_list lub select_item)
if (ecomObj.item_list_name !== undefined) ga4Obj.item_list_name = ecomObj.item_list_name;
if (ecomObj.item_list_id !== undefined) ga4Obj.item_list_id = ecomObj.item_list_id;
// Parametry dla zakupu (purchase) i zwrotu (refund)
if (eventName === 'purchase' || eventName === 'refund') {
if (ecomObj.transaction_id) ga4Obj.transaction_id = ecomObj.transaction_id;
else if (ecomObj.id) ga4Obj.transaction_id = ecomObj.id;
if (ecomObj.tax !== undefined) ga4Obj.tax = ecomObj.tax;
if (ecomObj.shipping !== undefined) ga4Obj.shipping = ecomObj.shipping;
if (ecomObj.affiliation !== undefined) ga4Obj.affiliation = ecomObj.affiliation;
}
// Parametry płatności i dostawy (Checkout)
if (eventName === 'add_payment_info' || eventName === 'purchase') {
if (ecomObj.payment_type !== undefined) ga4Obj.payment_type = ecomObj.payment_type;
}
if (eventName === 'add_shipping_info' || eventName === 'purchase') {
if (ecomObj.shipping_tier !== undefined) ga4Obj.shipping_tier = ecomObj.shipping_tier;
}
return ga4Obj;
___WEB_PERMISSIONS___
[
{
"instance": {
"key": {
"publicId": "read_data_layer",
"versionId": "1"
},
"param": [
{
"key": "allowedKeys",
"value": {
"type": 1,
"string": "any"
}
}
]
},
"clientAnnotations": {
"isEditedByUser": true
},
"isRequired": true
}
]
___TESTS___
scenarios:
- name: Basic event - view_item
code: |-
mock('copyFromDataLayer', (key) => {
if (key === 'event') return 'view_item';
if (key === 'ecommerce') {
return {
value: 199.99,
currency: 'PLN',
items: [{ item_id: 'SKU-1' }],
transaction_id: 'IGNORE_ME' // To nie powinno zostać pobrane
};
}
});
let result = runCode();
assertThat(result.value).isEqualTo(199.99);
assertThat(result.currency).isEqualTo('PLN');
assertThat(result.items.length).isEqualTo(1);
// Zdarzenie to nie 'purchase', więc transaction_id powinno być zignorowane
assertThat(result.transaction_id).isUndefined();
- name: Full purchase event
code: |-
mock('copyFromDataLayer', (key) => {
if (key === 'event') return 'purchase';
if (key === 'ecommerce') {
return {
value: 500,
currency: 'EUR',
transaction_id: 'ORDER-123',
tax: 23,
shipping: 15,
affiliation: 'Google',
payment_type: 'Credit Card',
shipping_tier: 'Express',
items: [{ item_id: 'SKU-2' }]
};
}
});
let result = runCode();
// Sprawdzamy czy przy zakupie pobrało wszystkie parametry
assertThat(result.transaction_id).isEqualTo('ORDER-123');
assertThat(result.tax).isEqualTo(23);
assertThat(result.shipping).isEqualTo(15);
assertThat(result.affiliation).isEqualTo('Google');
assertThat(result.payment_type).isEqualTo('Credit Card');
assertThat(result.shipping_tier).isEqualTo('Express');
- name: Fallback to eventModel and id
code: |-
mock('copyFromDataLayer', (key) => {
if (key === 'event') return 'purchase';
if (key === 'ecommerce') return undefined; // Brak ecommerce
if (key === 'eventModel') {
return {
value: 50,
currency: 'USD',
id: 'ORDER-999', // W eventModel często jest id zamiast transaction_id
items: [{ item_id: 'SKU-3' }]
};
}
});
let result = runCode();
// Skrypt powinien zmapować 'id' na 'transaction_id' dla GA4
assertThat(result.transaction_id).isEqualTo('ORDER-999');
assertThat(result.value).isEqualTo(50);
- name: No ecommerce data available
code: |-
mock('copyFromDataLayer', (key) => {
if (key === 'event') return 'add_to_cart';
if (key === 'ecommerce') return undefined;
if (key === 'eventModel') return undefined;
});
let result = runCode();
assertThat(result).isUndefined();
___NOTES___
Created on 18.03.2026, 14:21:01