@mhubcloud/tms_core 3.3.0-beta.1 → 3.3.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -57,10 +57,7 @@ var crypto = __toESM(require("crypto"));
57
57
  var appInsights = __toESM(require("applicationinsights"));
58
58
  var aiClient = null;
59
59
  if (process.env.APPLICATIONINSIGHTS_CONNECTION_STRING || process.env.APPINSIGHTS_INSTRUMENTATIONKEY) {
60
- const samplingLevel = process.env.Sampling ?? "12.5";
61
- appInsights.setup().setAutoCollectDependencies(false).setAutoCollectConsole(true, false).setSendLiveMetrics(false).setAutoCollectRequests(false).setAutoCollectPerformance(false).setUseDiskRetryCaching(false);
62
- appInsights.defaultClient.config.samplingPercentage = parseFloat(samplingLevel);
63
- appInsights.start();
60
+ appInsights.setup().setAutoCollectDependencies(false).setAutoCollectConsole(true, false).setSendLiveMetrics(false).setAutoCollectRequests(false).setAutoCollectPerformance(false).setUseDiskRetryCaching(false).start();
64
61
  aiClient = appInsights.defaultClient;
65
62
  }
66
63
  var EventPublisherBase = class {
@@ -92,12 +89,11 @@ function logMessage(level, message, properties) {
92
89
  properties
93
90
  });
94
91
  }
95
- function logEvent(publisher2, event, region, sampling) {
92
+ function logEvent(publisher2, event, region) {
96
93
  const properties = {
97
94
  publisher: publisher2,
98
95
  event,
99
- region,
100
- sampling
96
+ region
101
97
  };
102
98
  logMessage(1, "Event dispatched to platform", properties);
103
99
  }
@@ -229,10 +225,10 @@ async function handlePlatformRequest({
229
225
  rawPlatformResponse,
230
226
  event.event
231
227
  );
232
- logEvent(source, event.event, event.region, process.env.Sampling);
228
+ logEvent(source, event.event, event.region);
233
229
  return processedPlatformResponse;
234
230
  } else {
235
- logEvent(source, event.event, event.region, process.env.Sampling);
231
+ logEvent(source, event.event, event.region);
236
232
  }
237
233
  }
238
234
  async function handleTestRequest(params) {
@@ -303,8 +299,7 @@ async function defaultPublisher(azureFunctionContext, serviceBusMessage, source,
303
299
  async function processMessage(message, log2, platformPublisher, trigger) {
304
300
  const logProperties = {
305
301
  source: platformPublisher.source,
306
- data: JSON.stringify(message),
307
- sampling: process.env.Sampling
302
+ data: JSON.stringify(message)
308
303
  };
309
304
  const publishers = trigger(message, log2);
310
305
  if (!publishers.length) {
@@ -482,6 +477,97 @@ var facebook = {
482
477
  }
483
478
  };
484
479
 
480
+ // src/utils/tokens/googleAdsToken.ts
481
+ var tokenCache = null;
482
+ var tokenPromise = null;
483
+ async function fetchGoogleAdsToken(config) {
484
+ if (tokenCache && tokenCache.createdAt + 3500 * 1e3 > Date.now()) {
485
+ return tokenCache;
486
+ }
487
+ if (!tokenPromise) {
488
+ tokenPromise = (async () => {
489
+ const tokenResponse = await fetch(`https://oauth2.googleapis.com/token`, {
490
+ method: "POST",
491
+ headers: {
492
+ // eslint-disable-next-line @typescript-eslint/naming-convention
493
+ "Content-Type": "application/x-www-form-urlencoded"
494
+ },
495
+ body: new URLSearchParams({
496
+ // eslint-disable-next-line @typescript-eslint/naming-convention
497
+ client_id: config.client.id,
498
+ // eslint-disable-next-line @typescript-eslint/naming-convention
499
+ client_secret: config.client.secret,
500
+ refreshToken: config.refreshToken,
501
+ // eslint-disable-next-line @typescript-eslint/naming-convention
502
+ grant_type: "refresh_token"
503
+ })
504
+ });
505
+ const parsedTokenResponse = await tokenResponse.json();
506
+ const createdAt = Date.now();
507
+ tokenCache = { token: parsedTokenResponse.access_token, createdAt };
508
+ tokenPromise = null;
509
+ return tokenCache;
510
+ })();
511
+ }
512
+ return tokenPromise;
513
+ }
514
+
515
+ // src/publishers/googleAds.ts
516
+ var googleAds = {
517
+ source: "GoogleAds",
518
+ /**
519
+ *Publishes data to Google Ads
520
+ * @param log Azure Function context.log
521
+ * @param config Publisher configuration
522
+ * @param data Data in publisher-friendly format to be published
523
+ * @param event Event for which the function is triggered
524
+ */
525
+ async publish(log2, config, data, event) {
526
+ if (!data.gclid && !data.wbraid && !data.gbraid && !data.user_identifiers) {
527
+ logMessage(1, `Excluded ${event.event} due to lack of identifiers`);
528
+ return;
529
+ }
530
+ const tokenData = await fetchGoogleAdsToken(config);
531
+ data.conversionAction = `customers/${config.customerId}/conversionActions/${config.conversionId}`;
532
+ const body = {
533
+ conversions: [data],
534
+ partialFailure: true,
535
+ validateOnly: false,
536
+ debugEnabled: false
537
+ };
538
+ const requestOptions = {
539
+ method: "POST",
540
+ headers: {
541
+ // eslint-disable-next-line @typescript-eslint/naming-convention
542
+ Authorization: `Bearer ${tokenData.token}`,
543
+ "developer-token": config.client.developerToken
544
+ },
545
+ body: JSON.stringify(body)
546
+ };
547
+ const baseUrl = `https://googleads.googleapis.com/v17/customers/${config.customerId}:uploadClickConversions`;
548
+ const response = await fetch(baseUrl, requestOptions);
549
+ const responseJson = await response.json();
550
+ const knownErrors = [
551
+ "The imported event has a conversion_date_time that precedes the click. Make sure your conversion_date_time is correct and try again., at conversions[0].conversion_date_time",
552
+ "The click ID or call is associated with an Ads account you don't have access to. Make sure you import conversions for accounts managed by your manager account., at conversions[0].gclid",
553
+ "The imported event can't be recorded because its click occurred before this conversion's click-through window. Make sure you import the most recent data., at conversions[0].gclid",
554
+ "The imported event includes an order ID that was previously recorded, so the event was not processed., at conversions[0].order_id",
555
+ "The imported event could not be attributed to a click. This may be because the event did not come from a Google Ads campaign., at conversions[0].gclid",
556
+ "The imported event can't be recorded because its click occurred before this conversion's click-through window. Make sure you import the most recent data., at conversions[0].conversion_action"
557
+ ];
558
+ if (responseJson.partialFailureError) {
559
+ logMessage(1, responseJson.partialFailureError.message);
560
+ if (!knownErrors.includes(responseJson.partialFailureError.message)) {
561
+ throw new Error(responseJson.partialFailureError.message);
562
+ }
563
+ } else if (responseJson.error) {
564
+ throw new Error(responseJson.error.message);
565
+ } else {
566
+ logEvent(this.source, event.event, event.region);
567
+ }
568
+ }
569
+ };
570
+
485
571
  // src/publishers/googleAnalytics4.ts
486
572
  var googleAnalytics4 = {
487
573
  source: "GoogleAnalytics4",
@@ -648,6 +734,8 @@ var publisher = {
648
734
  // eslint-disable-next-line @typescript-eslint/naming-convention
649
735
  CJ: cj,
650
736
  // eslint-disable-next-line @typescript-eslint/naming-convention
737
+ GoogleAds: googleAds,
738
+ // eslint-disable-next-line @typescript-eslint/naming-convention
651
739
  GoogleAnalytics4: googleAnalytics4,
652
740
  // eslint-disable-next-line @typescript-eslint/naming-convention
653
741
  UniversalAnalytics: universalAnalytics,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhubcloud/tms_core",
3
- "version": "3.3.0-beta.1",
3
+ "version": "3.3.0-beta.3",
4
4
  "description": "Core function for mHub Cloud TMS publishers",
5
5
  "homepage": "https://mhubcloud.com/",
6
6
  "license": "Apache 2.0",
@@ -40,6 +40,6 @@
40
40
  "scripts": {
41
41
  "test": "mocha ./tests/*.js --local-settings=./local.settings.json --timeout 100000",
42
42
  "dev": "ts-node index.ts",
43
- "build": "tsup ./src/index.ts --format cjs --target node18"
43
+ "build": "tsup ./src/index.ts --format cjs --target node20"
44
44
  }
45
45
  }
@@ -4,8 +4,8 @@ const SOURCE = "f_TableStorage";
4
4
 
5
5
  module.exports = {
6
6
  /**
7
- * Processed data comming from EventHub to data for further processing
8
- * @param {Object} data The data comming from EventHub
7
+ * Processed data coming from EventHub to data for further processing
8
+ * @param {Object} data The data coming from EventHub
9
9
  * @returns {Object} Data for further processing
10
10
  */
11
11
  parse: function parse(data, context) {
@@ -8,7 +8,7 @@ import { TypeSafeObject } from './types/UtilTypes';
8
8
  import * as utils from './utils/utils';
9
9
 
10
10
  /**
11
- * Implements the Azure Function, called for set of events received via Event Hub
11
+ * Implements the Azure Function, called for set of events received via Service Bus
12
12
  * @deprecated Udelat novou metodu, ktera bude spravne a bude inicializovat classu
13
13
  * @param azureFunctionContext Azure Function Context
14
14
  * @param serviceBusMessage Message received from Service Bus
@@ -75,7 +75,6 @@ async function processMessage(
75
75
  const logProperties: Telemetry['properties'] = {
76
76
  source: platformPublisher.source,
77
77
  data: JSON.stringify(message),
78
- sampling: process.env.Sampling,
79
78
  };
80
79
  const publishers = trigger(message, log);
81
80
  if (!publishers.length) {
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ import { defaultPublisher } from './defaultPublisher';
2
2
  import { affiliatePort } from './publishers/affiliatePort';
3
3
  import { cj } from './publishers/cj';
4
4
  import { facebook } from './publishers/facebook';
5
+ import { googleAds } from './publishers/googleAds';
5
6
  import { googleAnalytics4 } from './publishers/googleAnalytics4';
6
7
  import { piano } from './publishers/piano';
7
8
  import { universalAnalytics } from './publishers/universalAnalytics';
@@ -14,6 +15,8 @@ export const publisher = {
14
15
  // eslint-disable-next-line @typescript-eslint/naming-convention
15
16
  CJ: cj,
16
17
  // eslint-disable-next-line @typescript-eslint/naming-convention
18
+ GoogleAds: googleAds,
19
+ // eslint-disable-next-line @typescript-eslint/naming-convention
17
20
  GoogleAnalytics4: googleAnalytics4,
18
21
  // eslint-disable-next-line @typescript-eslint/naming-convention
19
22
  UniversalAnalytics: universalAnalytics,
@@ -0,0 +1,96 @@
1
+ import * as utils from './../utils/utils';
2
+ import {
3
+ PlatformPublisher,
4
+ PlatformRequestOptions,
5
+ } from '../types/PlatformPublisher';
6
+ import {
7
+ fetchGoogleAdsToken,
8
+ GoogleAdsConfig,
9
+ } from '../utils/tokens/googleAdsToken';
10
+
11
+ interface GoogleAdsData {
12
+ gclid?: string;
13
+ wbraid?: string;
14
+ gbraid?: string;
15
+ // eslint-disable-next-line @typescript-eslint/naming-convention
16
+ user_identifiers: Record<string, unknown>[];
17
+ conversionAction?: string;
18
+ [x: string]: unknown;
19
+ }
20
+
21
+ export const googleAds: PlatformPublisher = {
22
+ source: 'GoogleAds',
23
+ /**
24
+ *Publishes data to Google Ads
25
+ * @param log Azure Function context.log
26
+ * @param config Publisher configuration
27
+ * @param data Data in publisher-friendly format to be published
28
+ * @param event Event for which the function is triggered
29
+ */
30
+ async publish(log, config, data, event) {
31
+ if (
32
+ !(data as GoogleAdsData).gclid &&
33
+ !(data as GoogleAdsData).wbraid &&
34
+ !(data as GoogleAdsData).gbraid &&
35
+ !(data as GoogleAdsData).user_identifiers
36
+ ) {
37
+ utils.logMessage(1, `Excluded ${event.event} due to lack of identifiers`);
38
+ return;
39
+ }
40
+
41
+ const tokenData = await fetchGoogleAdsToken(config);
42
+
43
+ data.conversionAction = `customers/${config.customerId}/conversionActions/${config.conversionId}`;
44
+
45
+ const body = {
46
+ conversions: [data],
47
+ partialFailure: true,
48
+ validateOnly: false,
49
+ debugEnabled: false,
50
+ };
51
+
52
+ const requestOptions = {
53
+ method: 'POST',
54
+ headers: {
55
+ // eslint-disable-next-line @typescript-eslint/naming-convention
56
+ Authorization: `Bearer ${tokenData.token}`,
57
+ 'developer-token': config.client.developerToken,
58
+ },
59
+ body: JSON.stringify(body),
60
+ };
61
+
62
+ const baseUrl = `https://googleads.googleapis.com/v17/customers/${config.customerId}:uploadClickConversions`;
63
+
64
+ const response = await fetch(baseUrl, requestOptions);
65
+ const responseJson: GoogleAdsResponse = await response.json();
66
+
67
+ const knownErrors = [
68
+ 'The imported event has a conversion_date_time that precedes the click. Make sure your conversion_date_time is correct and try again., at conversions[0].conversion_date_time',
69
+ "The click ID or call is associated with an Ads account you don't have access to. Make sure you import conversions for accounts managed by your manager account., at conversions[0].gclid",
70
+ "The imported event can't be recorded because its click occurred before this conversion's click-through window. Make sure you import the most recent data., at conversions[0].gclid",
71
+ 'The imported event includes an order ID that was previously recorded, so the event was not processed., at conversions[0].order_id',
72
+ 'The imported event could not be attributed to a click. This may be because the event did not come from a Google Ads campaign., at conversions[0].gclid',
73
+ "The imported event can't be recorded because its click occurred before this conversion's click-through window. Make sure you import the most recent data., at conversions[0].conversion_action",
74
+ ];
75
+
76
+ if (responseJson.partialFailureError) {
77
+ utils.logMessage(1, responseJson.partialFailureError.message);
78
+ if (!knownErrors.includes(responseJson.partialFailureError.message)) {
79
+ throw new Error(responseJson.partialFailureError.message);
80
+ }
81
+ } else if (responseJson.error) {
82
+ throw new Error(responseJson.error.message);
83
+ } else {
84
+ utils.logEvent(this.source, event.event, event.region);
85
+ }
86
+ },
87
+ };
88
+
89
+ interface GoogleAdsResponse {
90
+ partialFailureError?: {
91
+ message: string;
92
+ };
93
+ error?: {
94
+ message: string;
95
+ };
96
+ }
@@ -0,0 +1,66 @@
1
+ let tokenCache: TokenCache | null = null;
2
+ let tokenPromise: Promise<TokenCache> | null = null;
3
+
4
+ export async function fetchGoogleAdsToken(
5
+ config: GoogleAdsConfig,
6
+ ): Promise<TokenCache> {
7
+ if (tokenCache && tokenCache.createdAt + 3500 * 1000 > Date.now()) {
8
+ return tokenCache;
9
+ }
10
+
11
+ if (!tokenPromise) {
12
+ tokenPromise = (async () => {
13
+ const tokenResponse = await fetch(`https://oauth2.googleapis.com/token`, {
14
+ method: 'POST',
15
+ headers: {
16
+ // eslint-disable-next-line @typescript-eslint/naming-convention
17
+ 'Content-Type': 'application/x-www-form-urlencoded',
18
+ },
19
+ body: new URLSearchParams({
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ client_id: config.client.id,
22
+ // eslint-disable-next-line @typescript-eslint/naming-convention
23
+ client_secret: config.client.secret,
24
+ refreshToken: config.refreshToken,
25
+ // eslint-disable-next-line @typescript-eslint/naming-convention
26
+ grant_type: 'refresh_token',
27
+ }),
28
+ });
29
+
30
+ // if (!tokenResponse.ok) {
31
+ // throw new Error('Access token fetch failed')
32
+ // }
33
+
34
+ const parsedTokenResponse: TokenResponse = await tokenResponse.json();
35
+ const createdAt = Date.now();
36
+
37
+ tokenCache = { token: parsedTokenResponse.access_token, createdAt };
38
+ tokenPromise = null;
39
+ return tokenCache;
40
+ })();
41
+ }
42
+
43
+ return tokenPromise;
44
+ }
45
+
46
+ interface TokenCache {
47
+ token: string;
48
+ createdAt: number;
49
+ }
50
+
51
+ interface TokenResponse {
52
+ // eslint-disable-next-line @typescript-eslint/naming-convention
53
+ access_token: string;
54
+ }
55
+
56
+ export interface GoogleAdsConfig {
57
+ client: {
58
+ id: string;
59
+ secret: string;
60
+ developerToken: string;
61
+ };
62
+ refreshToken: string;
63
+ customerId: string;
64
+ conversionId: string;
65
+ [x: string]: unknown;
66
+ }
@@ -16,8 +16,6 @@ if (
16
16
  process.env.APPLICATIONINSIGHTS_CONNECTION_STRING ||
17
17
  process.env.APPINSIGHTS_INSTRUMENTATIONKEY
18
18
  ) {
19
- const samplingLevel = process.env.SamplingLevel ?? '12.5';
20
-
21
19
  appInsights
22
20
  .setup() // Set environment variable APPLICATIONINSIGHTS_CONNECTION_STRING, so setup() can be called w/o parameters
23
21
  .setAutoCollectDependencies(false)
@@ -25,10 +23,8 @@ if (
25
23
  .setSendLiveMetrics(false)
26
24
  .setAutoCollectRequests(false)
27
25
  .setAutoCollectPerformance(false)
28
- .setUseDiskRetryCaching(false);
29
- appInsights.defaultClient.config.samplingPercentage =
30
- parseFloat(samplingLevel);
31
- appInsights.start();
26
+ .setUseDiskRetryCaching(false)
27
+ .start();
32
28
  aiClient = appInsights.defaultClient;
33
29
  }
34
30
 
@@ -82,10 +78,9 @@ export function logEvent(
82
78
  region: string,
83
79
  ): void {
84
80
  const properties: Telemetry['properties'] = {
85
- publisher,
86
- event,
87
- region,
88
- sampling: process.env.SamplingLevel,
81
+ publisher: publisher,
82
+ event: event,
83
+ region: region,
89
84
  };
90
85
  logMessage(1, 'Event dispatched to platform', properties);
91
86
  }
@@ -343,7 +338,9 @@ export async function handlePlatformRequest({
343
338
  rawPlatformResponse,
344
339
  event.event,
345
340
  );
341
+
346
342
  logEvent(source, event.event, event.region);
343
+
347
344
  return processedPlatformResponse;
348
345
  } else {
349
346
  logEvent(source, event.event, event.region);
@@ -109,7 +109,7 @@ class AffiliatePortPurchasePublisher extends utils.EventPublisherBase {
109
109
  /**
110
110
  * Maps `purchase` event data to AffiliatePort payload
111
111
  * @param {Object} data `purchase` event data
112
- * @returns {Object} Data mapped from incomming Event Hub message to platform payload
112
+ * @returns {Object} Data mapped from incoming Service Bus message to platform payload
113
113
  */
114
114
  map(data) {
115
115
  return {
package/tests/CJ.js CHANGED
@@ -131,7 +131,7 @@ class CJPurchasePublisher extends utils.EventPublisherBase {
131
131
  /**
132
132
  * Converts input data to publishing payload data understood by the publisher
133
133
  * @param {Object} data `purchase` event data
134
- * @returns {Object} Data mapped from incomming Event Hub message to platform payload
134
+ * @returns {Object} Data mapped from incoming Service Bus message to platform payload
135
135
  */
136
136
  map(data, log) {
137
137
  const ret = {
package/tests/Facebook.js CHANGED
@@ -86,7 +86,7 @@ class FBPurchasePublisher extends utils.EventPublisherBase {
86
86
  /**
87
87
  * Maps `purchase` event data to Facebook payload
88
88
  * @param {Object} data `purchase` event data
89
- * @returns {Object} Data mapped from incomming Event Hub message to platform payload
89
+ * @returns {Object} Data mapped from incoming Service Bus message to platform payload
90
90
  */
91
91
  map(data) {
92
92
  return {
@@ -0,0 +1,127 @@
1
+ const publisher = require('../dist/index.js').publisher.GoogleAds;
2
+ const defaultPublisher = require('../dist/index.js').DefaultPublisher;
3
+ const utils = require('../dist/index.js').utils;
4
+ const testUtils = require('../dist/index.js').testUtils;
5
+ const localSettings = require('../local.settings.json');
6
+ process.env = { ...process.env, ...localSettings };
7
+
8
+ describe('test GoogleAds publisher', function () {
9
+ it('purchase', async function () {
10
+ const serviceBusMessage = {
11
+ currencyCode: 'CZK',
12
+ event: {
13
+ region: 'MAIN',
14
+ id: '115169112-4870.1657003407533',
15
+ code: 'purchase',
16
+ },
17
+ session: {
18
+ userAgent:
19
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
20
+ ip: '89.177.126.237',
21
+ referrer: 'https://crossmasters.com/',
22
+ },
23
+ referrer: 'https://crossmasters.com/',
24
+ permissions: [],
25
+ identity: {
26
+ piano: {
27
+ id: '1657003393413.319297501',
28
+ },
29
+ },
30
+ publisher: {
31
+ code: 'mhubcloud.com',
32
+ tm: 'GTM-N7K9L4X',
33
+ tmv: '494',
34
+ },
35
+ $schema: '/mhub/purchase',
36
+ id: '20162351',
37
+ revenue: 440,
38
+ products: [
39
+ {
40
+ id: 'Car',
41
+ price: 440,
42
+ quantity: 1,
43
+ },
44
+ ],
45
+ enqueuedAt: 1657003409370,
46
+ ads: [
47
+ {
48
+ adPlatform: 'googleads',
49
+ adCodes: {
50
+ gclid: 'mhubcloud',
51
+ },
52
+ visitAt: 1727173492000,
53
+ },
54
+ ],
55
+ };
56
+ await test(serviceBusMessage);
57
+ });
58
+ });
59
+
60
+ /**
61
+ * Test function
62
+ * @param [object] object obsahující nastavení testovací parametry
63
+ */
64
+ async function test(serviceBusMessage) {
65
+ await defaultPublisher(
66
+ testUtils.context,
67
+ serviceBusMessage,
68
+ 'GoogleAds',
69
+ publisher,
70
+ trigger,
71
+ );
72
+ }
73
+
74
+ function trigger(data) {
75
+ const publishers = [];
76
+ let publisher;
77
+
78
+ // Dummy config, replace with your own
79
+ const config = {
80
+ client: {
81
+ id: process.env.Publisher_GoogleAds_ClientID,
82
+ secret: process.env.Publisher_GoogleAds_ClientSecret,
83
+ developerToken: process.env.Publisher_GoogleAds_DeveloperToken,
84
+ },
85
+ refreshToken:
86
+ // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
87
+ process.env['Publisher_GoogleAds_RefreshToken_' + data.event.region],
88
+ customerId:
89
+ // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
90
+ process.env['Publisher_GoogleAds_CustomerID_' + data.event.region],
91
+ conversionId: process.env.Publisher_GoogleAds_ConversionID_purchase_MAIN,
92
+ };
93
+
94
+ switch (data.event?.code) {
95
+ case 'purchase':
96
+ publisher = new GoogleAdsPurchasePublisher(config);
97
+ publishers.push(publisher);
98
+ break;
99
+ }
100
+ return publishers;
101
+ }
102
+
103
+ class GoogleAdsPurchasePublisher extends utils.EventPublisherBase {
104
+ /**
105
+ * Maps `purchase` event data to GoogleAds payload
106
+ * @param {Object} data `purchase` event data
107
+ * @returns {Object} Data mapped from incoming Service Bus message to platform payload
108
+ */
109
+ map(data) {
110
+ const dateTime = new Date(data.enqueuedAt);
111
+ const dateString =
112
+ dateTime.toISOString().replace('T', ' ').split('.')[0] + '+00:00';
113
+ const gclid = utils.extractAdCode(data, 'googleads', 'gclid')?.code;
114
+ const wbraid = utils.extractAdCode(data, 'googleads', 'wbraid')?.code;
115
+ const gbraid = utils.extractAdCode(data, 'googleads', 'gbraid')?.code;
116
+
117
+ return {
118
+ gclid: gclid,
119
+ wbraid: gclid || gbraid ? undefined : wbraid,
120
+ gbraid: gclid || wbraid ? undefined : gbraid,
121
+ orderId: data.event.id,
122
+ conversionDateTime: dateString,
123
+ currencyCode: data.currencyCode, // e.g. EUR
124
+ conversionValue: data.value ? data.value : 0.01, // e.g. 142.52
125
+ };
126
+ }
127
+ }
package/tests/Piano.js CHANGED
@@ -80,7 +80,7 @@ class PianoPurchasePublisher extends utils.EventPublisherBase {
80
80
  /**
81
81
  * Converts input data to publishing payload data understood by the publisher
82
82
  * @param {Object} data `purchase` event data
83
- * @returns {Object} Data mapped from incomming Event Hub message to platform payload
83
+ * @returns {Object} Data mapped from incoming Service Bus message to platform payload
84
84
  */
85
85
  map(data) {
86
86
  return {