diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js index c31bc74bf1..292a980a93 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js @@ -1,18 +1,9 @@ /* eslint-disable @typescript-eslint/naming-convention */ const lodash = require('lodash'); const get = require('get-value'); -// const { RedisError } = require('@rudderstack/integrations-lib'); const stats = require('../../../../util/stats'); -const { - getShopifyTopic, - // createPropertiesForEcomEvent, - extractEmailFromPayload, - getAnonymousIdAndSessionId, - // getHashLineItems, -} = require('../../../../v0/sources/shopify/util'); -// const logger = require('../../../logger'); +const { getShopifyTopic, extractEmailFromPayload } = require('../../../../v0/sources/shopify/util'); const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../../../v0/util'); -// const { RedisDB } = require('../../../util/redis/redisConnector'); const Message = require('../../../../v0/sources/message'); const { EventType } = require('../../../../constants'); const { @@ -28,6 +19,7 @@ const { const { createPropertiesForEcomEventFromWebhook, getProductsFromLineItems, + getAnonymousIdFromAttributes, } = require('./serverSideUtlis'); const NO_OPERATION_SUCCESS = { @@ -128,12 +120,9 @@ const processEvent = async (inputEvent, metricMetadata) => { message.setProperty('traits.email', email); } } + // attach anonymousId if the event is track event using note_attributes if (message.type !== EventType.IDENTIFY) { - const { anonymousId } = await getAnonymousIdAndSessionId( - message, - { shopifyTopic, ...metricMetadata }, - null, - ); + const anonymousId = getAnonymousIdFromAttributes(event); if (isDefinedAndNotNull(anonymousId)) { message.setProperty('anonymousId', anonymousId); } diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js index a611d1d8dc..4a2839103b 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js @@ -1,6 +1,7 @@ const { getProductsFromLineItems, createPropertiesForEcomEventFromWebhook, + getAnonymousIdFromAttributes, } = require('./serverSideUtlis'); const { constructPayload } = require('../../../../v0/util'); @@ -109,4 +110,21 @@ describe('serverSideUtils.js', () => { }); }); }); + + describe('getAnonymousIdFromAttributes', () => { + // Handles empty note_attributes array gracefully + it('should return null when note_attributes is an empty array', async () => { + const event = { note_attributes: [] }; + const result = await getAnonymousIdFromAttributes(event); + expect(result).toBeNull(); + }); + + it('get anonymousId from noteAttributes', async () => { + const event = { + note_attributes: [{ name: 'rudderAnonymousId', value: '123456' }], + }; + const result = await getAnonymousIdFromAttributes(event); + expect(result).toEqual('123456'); + }); + }); }); diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js index eed03de71f..951fa479e4 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -1,5 +1,5 @@ +const { isDefinedAndNotNull } = require('@rudderstack/integrations-lib'); const { constructPayload } = require('../../../../v0/util'); - const { lineItemsMappingJSON, productMappingJSON, @@ -17,7 +17,6 @@ const getProductsFromLineItems = (lineItems, mapping) => { } const products = []; lineItems.forEach((lineItem) => { - // const product = constructPayload(lineItem, lineItemsMappingJSON); const product = constructPayload(lineItem, mapping); products.push(product); }); @@ -39,7 +38,24 @@ const createPropertiesForEcomEventFromWebhook = (message) => { return mappedPayload; }; +/** + * Returns the anonymousId from the noteAttributes array in the webhook event + * @param {Object} event + * @returns {String} anonymousId + */ +const getAnonymousIdFromAttributes = (event) => { + if (!isDefinedAndNotNull(event) || !isDefinedAndNotNull(event.note_attributes)) { + return null; // Return early if event or note_attributes is invalid + } + + const noteAttributes = event.note_attributes; + const rudderAnonymousIdObject = noteAttributes.find((attr) => attr.name === 'rudderAnonymousId'); + + return rudderAnonymousIdObject ? rudderAnonymousIdObject.value : null; +}; + module.exports = { createPropertiesForEcomEventFromWebhook, getProductsFromLineItems, + getAnonymousIdFromAttributes, }; diff --git a/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js index 0c1007f311..46ae59e0cf 100644 --- a/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js +++ b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js @@ -14,7 +14,7 @@ const { function getNestedValue(object, path) { const keys = path.split('.'); - return keys.reduce((nestedObject, key) => nestedObject && nestedObject[key], object); + return keys.reduce((nestedObject, key) => nestedObject?.[key], object); } function setNestedValue(object, path, value) { diff --git a/test/integrations/sources/shopify/constants.ts b/test/integrations/sources/shopify/constants.ts index f9df305841..af53a3180e 100644 --- a/test/integrations/sources/shopify/constants.ts +++ b/test/integrations/sources/shopify/constants.ts @@ -83,6 +83,21 @@ export const dummyContext = { }, }; +export const note_attributes = [ + { + name: 'cartId', + value: '9c623f099fc8819aa4d6a958b65dfe7d', + }, + { + name: 'cartToken', + value: 'Z2NwLXVzLWVhc3QxOjAxSkQzNUFXVEI4VkVUNUpTTk1LSzBCMzlF', + }, + { + name: 'rudderAnonymousId', + value: '50ead33e-d763-4854-b0ab-765859ef05cb', + }, +]; + export const responseDummyContext = { document: { location: { diff --git a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts index ade496efb7..a154ccb890 100644 --- a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts +++ b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts @@ -1,7 +1,6 @@ // This file contains the test scenarios for the server-side events from the Shopify GraphQL API for // the v1 transformation flow -import { mockFns } from '../mocks'; -import { dummySourceConfig } from '../constants'; +import { dummySourceConfig, note_attributes } from '../constants'; export const checkoutEventsTestScenarios = [ { @@ -27,7 +26,7 @@ export const checkoutEventsTestScenarios = [ updated_at: '2024-11-05T21:22:02-05:00', landing_site: '/', note: '', - note_attributes: [], + note_attributes, referring_site: '', shipping_lines: [], shipping_address: [], @@ -145,7 +144,7 @@ export const checkoutEventsTestScenarios = [ updated_at: '2024-11-05T21:22:02-05:00', landing_site: '/', note: '', - note_attributes: [], + note_attributes, referring_site: '', shipping_lines: [], shipping_address: [], @@ -237,7 +236,7 @@ export const checkoutEventsTestScenarios = [ traits: { shippingAddress: [], }, - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, @@ -269,7 +268,7 @@ export const checkoutEventsTestScenarios = [ created_at: '2024-09-16T03:50:1500:00', updated_at: '2024-09-17T03:29:02-04:00', note: '', - note_attributes: [], + note_attributes, shipping_address: { first_name: 'testuser', address1: 'oakwood bridge', @@ -396,7 +395,7 @@ export const checkoutEventsTestScenarios = [ output: { batch: [ { - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', context: { cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', integration: { @@ -415,7 +414,7 @@ export const checkoutEventsTestScenarios = [ created_at: '2024-09-16T03:50:1500:00', updated_at: '2024-09-17T03:29:02-04:00', note: '', - note_attributes: [], + note_attributes, shipping_address: { first_name: 'testuser', address1: 'oakwood bridge', @@ -680,7 +679,7 @@ export const checkoutEventsTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, number: 17, order_number: 1017, order_status_url: @@ -988,7 +987,7 @@ export const checkoutEventsTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, number: 17, order_number: 1017, order_status_url: @@ -1289,7 +1288,7 @@ export const checkoutEventsTestScenarios = [ }, }, timestamp: '2024-11-06T02:54:50.000Z', - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, @@ -1326,6 +1325,7 @@ export const checkoutEventsTestScenarios = [ current_total_tax: '0.00', email: 'henry@wfls.com', name: '#1017', + note_attributes, order_number: 1017, order_status_url: 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', @@ -1486,6 +1486,7 @@ export const checkoutEventsTestScenarios = [ current_total_tax: '0.00', email: 'henry@wfls.com', name: '#1017', + note_attributes, order_number: 1017, order_status_url: 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', @@ -1675,7 +1676,7 @@ export const checkoutEventsTestScenarios = [ }, }, timestamp: '2024-11-06T02:54:50.000Z', - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, @@ -1684,4 +1685,4 @@ export const checkoutEventsTestScenarios = [ }, }, }, -].map((d1) => ({ ...d1, mockFns })); +]; diff --git a/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts index f04fd7e08e..d68d0a8f59 100644 --- a/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts +++ b/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts @@ -1,7 +1,7 @@ // This file contains the test scenarios for the server-side events from the Shopify GraphQL API for // the v1 transformation flow import { mockFns } from '../mocks'; -import { dummySourceConfig } from '../constants'; +import { dummySourceConfig, note_attributes } from '../constants'; export const genericTrackTestScenarios = [ { @@ -24,6 +24,7 @@ export const genericTrackTestScenarios = [ token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', line_items: [], note: '', + note_attributes, updated_at: '2024-09-17T08:15:13.280Z', created_at: '2024-09-16T03:50:15.478Z', }, @@ -43,7 +44,7 @@ export const genericTrackTestScenarios = [ output: { batch: [ { - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', context: { integration: { name: 'SHOPIFY', @@ -58,6 +59,7 @@ export const genericTrackTestScenarios = [ id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', line_items: [], note: '', + note_attributes, token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', updated_at: '2024-09-17T08:15:13.280Z', }, @@ -149,7 +151,7 @@ export const genericTrackTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, order_number: 1017, original_total_additional_fees_set: null, original_total_duties_set: null, @@ -363,7 +365,7 @@ export const genericTrackTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, order_number: 1017, original_total_additional_fees_set: null, original_total_duties_set: null, @@ -545,7 +547,7 @@ export const genericTrackTestScenarios = [ traits: { email: 'henry@wfls.com', }, - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], },