Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: snapchat conversion introduce missing fields #2704

Merged
merged 11 commits into from
Oct 11, 2023
174 changes: 125 additions & 49 deletions src/v0/destinations/snapchat_conversion/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,43 @@
response.body.JSON = removeUndefinedAndNullValues(payload);
return response;
}
const populateHashedTraitsValues = (payload, message) => {
const firstName = getFieldValueFromMessage(message, 'firstName');
const lastName = getFieldValueFromMessage(message, 'lastName');
const middleName = getFieldValueFromMessage(message, 'middleName');
const city = getFieldValueFromMessage(message, 'city');
const state = getFieldValueFromMessage(message, 'state');
const zip = getFieldValueFromMessage(message, 'zipcode');
const updatedPayload = {
...payload,
hashed_first_name_sha: firstName
? getHashedValue(firstName.toString().toLowerCase().trim())
: undefined,
hashed_middle_name_sha: middleName
? getHashedValue(middleName.toString().toLowerCase().trim())
: undefined,
hashed_last_name_sha: lastName
? getHashedValue(lastName.toString().toLowerCase().trim())
: undefined,
hashed_city_sha: city ? getHashedValue(city.toString().toLowerCase().trim()) : undefined,
hashed_zip: zip ? getHashedValue(zip.toString().toLowerCase().trim()) : undefined,
hashed_state_sha: state ? getHashedValue(state.toString().toLowerCase().trim()) : undefined,
};
return updatedPayload;
};

/**
* Seperate out hashing operations into one function
* @param {*} payload
* @param {*} message
* @returns updatedPayload
*/
function populateHashedValues(payload, message) {
const updatedPayload = payload;
const populateHashedValues = (payload, message) => {
const email = getFieldValueFromMessage(message, 'email');
const phone = getNormalizedPhoneNumber(message);
const ip = message.context?.ip || message.request_ip;

const updatedPayload = populateHashedTraitsValues(payload, message);
if (email) {
updatedPayload.hashed_email = getHashedValue(email.toString().toLowerCase().trim());
}
Expand All @@ -85,14 +109,82 @@
);
}
return updatedPayload;
}
};
const getEventProperties = (message) => ({
description: get(message, 'properties.description'),
brands: Array.isArray(message.properties?.brands) ? get(message, 'properties.brands') : undefined,
customer_status: get(message, 'properties.customer_status'),
uuid_c1: get(message, 'properties.uuid_c1'),
level: get(message, 'properties.level'),
click_id: get(message, 'properties.click_id'),
event_tag: get(message, 'properties.event_tag'),
country: getFieldValueFromMessage(message, 'country'),
region: getFieldValueFromMessage(message, 'region'),
user_agent: message.context?.userAgent?.toString()?.toLowerCase(),
});
const validateEventConfiguration = (eventConversionType, pixelId, snapAppId, appId) => {
if ((eventConversionType === 'WEB' || eventConversionType === 'OFFLINE') && !pixelId) {
throw new ConfigurationError('Pixel Id is required for web and offline events');
}

// Returns the response for the track event after constructing the payload and setting necessary fields
function trackResponseBuilder(message, { Config }, mappedEvent) {
let payload = {};
const event = mappedEvent.trim().replace(/\s+/g, '_');
if (eventConversionType === 'MOBILE_APP' && !(appId && snapAppId)) {
if (!appId) {
throw new ConfigurationError('App Id is required for app events');
} else {
throw new ConfigurationError('Snap App Id is required for app events');
}
}
};
anantjain45823 marked this conversation as resolved.
Show resolved Hide resolved
const validateRequiredFields = (payload) => {
if (
!payload.hashed_email &&
!payload.hashed_phone_number &&
!payload.hashed_mobile_ad_id &&
!(payload.hashed_ip_address && payload.user_agent)

Check warning on line 143 in src/v0/destinations/snapchat_conversion/transform.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/snapchat_conversion/transform.js#L141-L143

Added lines #L141 - L143 were not covered by tests
) {
throw new InstrumentationError(

Check warning on line 145 in src/v0/destinations/snapchat_conversion/transform.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/snapchat_conversion/transform.js#L145

Added line #L145 was not covered by tests
'At least one of email or phone or advertisingId or ip and userAgent is required',
);
}
};
const addSpecificEventDetails = (
message,
payload,
eventConversionType,
pixelId,
snapAppId,
appId,
) => {
const updatedPayload = { ...payload };
if (eventConversionType === 'WEB') {
updatedPayload.pixel_id = pixelId;
updatedPayload.page_url = getFieldValueFromMessage(message, 'pageUrl');
}

const { apiKey, pixelId, snapAppId, appId, deduplicationKey, enableDeduplication } = Config;
if (eventConversionType === 'MOBILE_APP') {
updatedPayload.snap_app_id = snapAppId;
updatedPayload.app_id = appId;
}

if (eventConversionType === 'OFFLINE') {
updatedPayload.pixel_id = pixelId;
}
return updatedPayload;
};
const handleDeduplication = (payload, enableDeduplication, deduplicationKey, message) => {
if (enableDeduplication) {
const dedupId = deduplicationKey || 'messageId';
const clientDedupId = get(message, dedupId);

Check warning on line 177 in src/v0/destinations/snapchat_conversion/transform.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/snapchat_conversion/transform.js#L177

Added line #L177 was not covered by tests
if (!clientDedupId) {
throw new InstrumentationError(

Check warning on line 179 in src/v0/destinations/snapchat_conversion/transform.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/snapchat_conversion/transform.js#L179

Added line #L179 was not covered by tests
'Deduplication enabled but no deduplication key provided in the message',
);
}
return clientDedupId;

Check warning on line 183 in src/v0/destinations/snapchat_conversion/transform.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/snapchat_conversion/transform.js#L183

Added line #L183 was not covered by tests
}
return undefined;
};
const getEventConversionType = (message) => {
const channel = get(message, 'channel');
let eventConversionType = message?.properties?.eventConversionType;
if (
Expand All @@ -105,18 +197,16 @@
} else {
eventConversionType = 'OFFLINE';
}
return eventConversionType;
};

if ((eventConversionType === 'WEB' || eventConversionType === 'OFFLINE') && !pixelId) {
throw new ConfigurationError('Pixel Id is required for web and offline events');
}

if (eventConversionType === 'MOBILE_APP' && !(appId && snapAppId)) {
if (!appId) {
throw new ConfigurationError('App Id is required for app events');
} else {
throw new ConfigurationError('Snap App Id is required for app events');
}
}
// Returns the response for the track event after constructing the payload and setting necessary fields
const trackResponseBuilder = (message, { Config }, mappedEvent) => {
let payload = {};
const event = mappedEvent.trim().replace(/\s+/g, '_');
const eventConversionType = getEventConversionType(message);
const { apiKey, pixelId, snapAppId, appId, deduplicationKey, enableDeduplication } = Config;
validateEventConfiguration(eventConversionType, pixelId, snapAppId, appId);

if (eventNameMapping[event.toLowerCase()]) {
// Snapchat standard events
Expand Down Expand Up @@ -192,21 +282,9 @@
throw new InstrumentationError(`Event ${event} doesn't match with Snapchat Events!`);
}

payload.event_tag = get(message, 'properties.event_tag');
payload = { ...payload, ...getEventProperties(message) };
payload = populateHashedValues(payload, message);

payload.user_agent = message.context?.userAgent?.toString().toLowerCase();

if (
!payload.hashed_email &&
!payload.hashed_phone_number &&
!payload.hashed_mobile_ad_id &&
!(payload.hashed_ip_address && payload.user_agent)
) {
throw new InstrumentationError(
'At least one of email or phone or advertisingId or ip and userAgent is required',
);
}
validateRequiredFields(payload);
payload.timestamp = getFieldValueFromMessage(message, 'timestamp');
const timeStamp = payload.timestamp;
if (timeStamp) {
Expand All @@ -224,17 +302,15 @@
}

payload.event_conversion_type = eventConversionType;
if (eventConversionType === 'WEB') {
payload.pixel_id = pixelId;
payload.page_url = getFieldValueFromMessage(message, 'pageUrl');
}
if (eventConversionType === 'MOBILE_APP') {
payload.snap_app_id = snapAppId;
payload.app_id = appId;
}
if (eventConversionType === 'OFFLINE') {
payload.pixel_id = pixelId;
}
payload = addSpecificEventDetails(
message,
payload,
eventConversionType,
pixelId,
snapAppId,
appId,
);
payload.client_dedup_id = handleDeduplication(enableDeduplication, deduplicationKey, message);

// adding for deduplication for more than one source
if (enableDeduplication) {
Expand All @@ -246,10 +322,10 @@
// build response
const response = buildResponse(apiKey, payload);
return response;
}
};

// Checks if there are any mapping events for the track event and returns them
function eventMappingHandler(message, destination) {
const eventMappingHandler = (message, destination) => {
let event = get(message, 'event');

if (!event) {
Expand All @@ -276,9 +352,9 @@
}

return [...mappedEvents];
}
};

function process(event) {
const process = (event) => {
const { message, destination } = event;
// const message = { ...incomingMessage };
if (!message.type) {
Expand All @@ -304,7 +380,7 @@
throw new InstrumentationError(`Event type ${messageType} is not supported`);
}
return response;
}
};

const processRouterDest = async (inputs, reqMetadata) => {
const errorRespEvents = checkInvalidRtTfEvents(inputs);
Expand Down
38 changes: 31 additions & 7 deletions test/__tests__/data/snapchat_conversion.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@
"context": {
"traits": {
"email": "[email protected]",
"phone": "+91 2111111 "
"phone": "+91 2111111 ",
"firstName": "john",
"middleName": "victor",
"lastName": "doe",
"city": "some_city",
"state": "some_state"
},
"app": {
"build": "1.0.0",
Expand Down Expand Up @@ -147,7 +152,9 @@
"properties": {
"query": "t-shirts",
"event_conversion_type": "web",
"number_items": 4
"number_items": 4,
"click_id": "some_click_id",
"description": "Products Searched event for conversion type offline"
},
"integrations": {
"All": true
Expand Down Expand Up @@ -183,7 +190,13 @@
"timestamp": "1650625078",
"event_conversion_type": "OFFLINE",
"pixel_id": "dummyPixelId",
"number_items": 4
"number_items": 4,
"click_id": "some_click_id",
"description": "Products Searched event for conversion type offline",
"hashed_first_name_sha": "96d9632f363564cc3032521409cf22a852f2032eec099ed5967c0d000cec607a",
"hashed_last_name_sha": "799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f",
"hashed_state_sha": "6db488fc98e30afdf67a05a6da916805b02891ce58f03970c6deff79129c5f1c",
"hashed_middle_name_sha": "99bde068af2d49ed7fc8b8fa79abe13a6059e0db320bb73459fd96624bb4b33f"
},
"JSON_ARRAY": {},
"XML": {},
Expand All @@ -202,7 +215,10 @@
"context": {
"traits": {
"email": "[email protected]",
"phone": "+91 2111111 "
"phone": "+91 2111111 ",
"country": "IN",
"zicode": "Sxp-12345",
"region": "some_region"
},
"app": {
"build": "1.0.0",
Expand Down Expand Up @@ -749,7 +765,10 @@
"context": {
"traits": {
"email": "[email protected]",
"phone": "+91 2111111 "
"phone": "+91 2111111 ",
"country": "IN",
"zipcode": "Sxp-12345",
"region": "some_region"
},
"app": {
"build": "1.0.0",
Expand Down Expand Up @@ -830,6 +849,9 @@
"event_type": "VIEW_CONTENT",
"item_ids": ["123", "123"],
"price": "56",
"country": "IN",
"hashed_zip": "cbb2704f5b334a0cec32e5463d1fd9355f6ef73987bfe0ebb8389b7617452152",
"region": "some_region",
"hashed_email": "73062d872926c2a556f17b36f50e328ddf9bff9d403939bd14b6c3b7f5a33fc2",
"hashed_phone_number": "bc77d64d7045fe44795ed926df37231a0cfb6ec6b74588c512790e9f143cc492",
"hashed_mobile_ad_id": "f9779d734aaee50f16ee0011260bae7048f1d9a128c62b6a661077875701edd2",
Expand Down Expand Up @@ -1007,14 +1029,15 @@
"type": "track",
"event": "Order Completed",
"properties": {
"brands": ["brand01", "brand02"],
"products": [
{
"product_id": "123",
"price": "14",
"quantity": 1
},
{
"product_id": "123",
"product_id": "124",
"price": 14,
"quantity": 3
}
Expand Down Expand Up @@ -1047,7 +1070,8 @@
"body": {
"JSON": {
"event_type": "PURCHASE",
"item_ids": ["123", "123"],
"item_ids": ["123", "124"],
"brands": ["brand01", "brand02"],
"price": "56",
"hashed_email": "73062d872926c2a556f17b36f50e328ddf9bff9d403939bd14b6c3b7f5a33fc2",
"hashed_phone_number": "bc77d64d7045fe44795ed926df37231a0cfb6ec6b74588c512790e9f143cc492",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"body": {
"JSON": {},
"JSON_ARRAY": {
"batch": "[{\"search_string\":\"t-shirts\",\"event_type\":\"SEARCH\",\"hashed_email\":\"73062d872926c2a556f17b36f50e328ddf9bff9d403939bd14b6c3b7f5a33fc2\",\"hashed_phone_number\":\"bc77d64d7045fe44795ed926df37231a0cfb6ec6b74588c512790e9f143cc492\",\"hashed_idfv\":\"54bd0b26a3d39dad90f5149db49b9fd9ba885f8e35d1d94cae69273f5e657b9f\",\"hashed_mobile_ad_id\":\"f9779d734aaee50f16ee0011260bae7048f1d9a128c62b6a661077875701edd2\",\"user_agent\":\"mozilla/5.0 (macintosh; intel mac os x 10_15_2) applewebkit/537.36 (khtml, like gecko) chrome/79.0.3945.88 safari/537.36\",\"timestamp\":\"1650625078\",\"event_conversion_type\":\"OFFLINE\",\"pixel_id\":\"dummyPixelId\"},{\"search_string\":\"t-shirts\",\"event_type\":\"SEARCH\",\"hashed_email\":\"73062d872926c2a556f17b36f50e328ddf9bff9d403939bd14b6c3b7f5a33fc2\",\"hashed_phone_number\":\"bc77d64d7045fe44795ed926df37231a0cfb6ec6b74588c512790e9f143cc492\",\"hashed_idfv\":\"54bd0b26a3d39dad90f5149db49b9fd9ba885f8e35d1d94cae69273f5e657b9f\",\"hashed_mobile_ad_id\":\"f9779d734aaee50f16ee0011260bae7048f1d9a128c62b6a661077875701edd2\",\"user_agent\":\"mozilla/5.0 (macintosh; intel mac os x 10_15_2) applewebkit/537.36 (khtml, like gecko) chrome/79.0.3945.88 safari/537.36\",\"timestamp\":\"1650625078\",\"event_conversion_type\":\"OFFLINE\",\"pixel_id\":\"dummyPixelId\"},{\"search_string\":\"t-shirts\",\"event_type\":\"SEARCH\",\"hashed_email\":\"73062d872926c2a556f17b36f50e328ddf9bff9d403939bd14b6c3b7f5a33fc2\",\"hashed_phone_number\":\"bc77d64d7045fe44795ed926df37231a0cfb6ec6b74588c512790e9f143cc492\",\"hashed_idfv\":\"54bd0b26a3d39dad90f5149db49b9fd9ba885f8e35d1d94cae69273f5e657b9f\",\"hashed_mobile_ad_id\":\"f9779d734aaee50f16ee0011260bae7048f1d9a128c62b6a661077875701edd2\",\"user_agent\":\"mozilla/5.0 (macintosh; intel mac os x 10_15_2) applewebkit/537.36 (khtml, like gecko) chrome/79.0.3945.88 safari/537.36\",\"timestamp\":\"1650625078\",\"event_conversion_type\":\"OFFLINE\",\"pixel_id\":\"dummyPixelId\"}]"
"batch": "[{\"search_string\":\"t-shirts\",\"event_type\":\"SEARCH\",\"user_agent\":\"mozilla/5.0 (macintosh; intel mac os x 10_15_2) applewebkit/537.36 (khtml, like gecko) chrome/79.0.3945.88 safari/537.36\",\"hashed_email\":\"73062d872926c2a556f17b36f50e328ddf9bff9d403939bd14b6c3b7f5a33fc2\",\"hashed_phone_number\":\"bc77d64d7045fe44795ed926df37231a0cfb6ec6b74588c512790e9f143cc492\",\"hashed_idfv\":\"54bd0b26a3d39dad90f5149db49b9fd9ba885f8e35d1d94cae69273f5e657b9f\",\"hashed_mobile_ad_id\":\"f9779d734aaee50f16ee0011260bae7048f1d9a128c62b6a661077875701edd2\",\"timestamp\":\"1650625078\",\"event_conversion_type\":\"OFFLINE\",\"pixel_id\":\"dummyPixelId\"},{\"search_string\":\"t-shirts\",\"event_type\":\"SEARCH\",\"user_agent\":\"mozilla/5.0 (macintosh; intel mac os x 10_15_2) applewebkit/537.36 (khtml, like gecko) chrome/79.0.3945.88 safari/537.36\",\"hashed_email\":\"73062d872926c2a556f17b36f50e328ddf9bff9d403939bd14b6c3b7f5a33fc2\",\"hashed_phone_number\":\"bc77d64d7045fe44795ed926df37231a0cfb6ec6b74588c512790e9f143cc492\",\"hashed_idfv\":\"54bd0b26a3d39dad90f5149db49b9fd9ba885f8e35d1d94cae69273f5e657b9f\",\"hashed_mobile_ad_id\":\"f9779d734aaee50f16ee0011260bae7048f1d9a128c62b6a661077875701edd2\",\"timestamp\":\"1650625078\",\"event_conversion_type\":\"OFFLINE\",\"pixel_id\":\"dummyPixelId\"},{\"search_string\":\"t-shirts\",\"event_type\":\"SEARCH\",\"user_agent\":\"mozilla/5.0 (macintosh; intel mac os x 10_15_2) applewebkit/537.36 (khtml, like gecko) chrome/79.0.3945.88 safari/537.36\",\"hashed_email\":\"73062d872926c2a556f17b36f50e328ddf9bff9d403939bd14b6c3b7f5a33fc2\",\"hashed_phone_number\":\"bc77d64d7045fe44795ed926df37231a0cfb6ec6b74588c512790e9f143cc492\",\"hashed_idfv\":\"54bd0b26a3d39dad90f5149db49b9fd9ba885f8e35d1d94cae69273f5e657b9f\",\"hashed_mobile_ad_id\":\"f9779d734aaee50f16ee0011260bae7048f1d9a128c62b6a661077875701edd2\",\"timestamp\":\"1650625078\",\"event_conversion_type\":\"OFFLINE\",\"pixel_id\":\"dummyPixelId\"}]"
},
"XML": {},
"FORM": {}
Expand Down
Loading