From 79ae6f95bdc2e92700469ef9e5a799a98d178f35 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Wed, 18 Dec 2024 08:13:21 +0530 Subject: [PATCH 1/3] fix: property and event name mappings in shopify v2 --- src/v1/sources/shopify/config.js | 12 +- .../webhookEventsMapping/identifyMapping.json | 112 ++++++++++++++++++ .../lineItemsMapping.json | 32 +++++ .../shopify/webhookEventsMapping/mapping.json | 10 ++ .../webhookEventsMapping/productMapping.json | 24 ++++ .../serverSideUtils.test.js | 6 +- .../webhookTransformations/serverSideUtlis.js | 5 +- .../pixelTestScenarios/CheckoutStepsTests.ts | 2 +- .../CheckoutEventsTests.ts | 32 ++--- 9 files changed, 210 insertions(+), 25 deletions(-) create mode 100644 src/v1/sources/shopify/webhookEventsMapping/identifyMapping.json create mode 100644 src/v1/sources/shopify/webhookEventsMapping/lineItemsMapping.json create mode 100644 src/v1/sources/shopify/webhookEventsMapping/mapping.json create mode 100644 src/v1/sources/shopify/webhookEventsMapping/productMapping.json diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index 5d88353d60..4115b6ae94 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -31,7 +31,7 @@ const PIXEL_EVENT_MAPPING = { checkout_address_info_submitted: 'Checkout Address Info Submitted', checkout_contact_info_submitted: 'Checkout Contact Info Submitted', checkout_shipping_info_submitted: 'Checkout Shipping Info Submitted', - payment_info_submitted: 'Payment Info Submitted', + payment_info_submitted: 'Payment Info Entered', search_submitted: 'Search Submitted', }; @@ -63,6 +63,14 @@ const checkoutStartedCompletedEventMappingJSON = JSON.parse( ), ); +const productMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'webhookEventsMapping', 'productMapping.json')), +); + +const lineItemsMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'webhookEventsMapping', 'lineItemsMapping.json')), +); + const pixelEventToCartTokenLocationMapping = { cart_viewed: 'properties.cart_id', checkout_address_info_submitted: commonCartTokenLocation, @@ -86,4 +94,6 @@ module.exports = { productToCartEventMappingJSON, checkoutStartedCompletedEventMappingJSON, pixelEventToCartTokenLocationMapping, + productMappingJSON, + lineItemsMappingJSON, }; diff --git a/src/v1/sources/shopify/webhookEventsMapping/identifyMapping.json b/src/v1/sources/shopify/webhookEventsMapping/identifyMapping.json new file mode 100644 index 0000000000..0367267502 --- /dev/null +++ b/src/v1/sources/shopify/webhookEventsMapping/identifyMapping.json @@ -0,0 +1,112 @@ +[ + { + "sourceKeys": "id", + "destKeys": "userId" + }, + { + "sourceKeys": "email", + "destKeys": "traits.email" + }, + + { + "sourceKeys": "first_name", + "destKeys": "traits.firstName" + }, + + { + "sourceKeys": "last_name", + "destKeys": "traits.lastName" + }, + + { + "sourceKeys": "phone", + "destKeys": "traits.phone" + }, + + { + "sourceKeys": "addresses", + "destKeys": "traits.addressList" + }, + + { + "sourceKeys": "default_address", + "destKeys": "traits.address" + }, + + { + "sourceKeys": "shipping_address", + "destKeys": "traits.shippingAddress" + }, + + { + "sourceKeys": "billing_address", + "destKeys": "traits.billingAddress" + }, + + { + "sourceKeys": "accepts_marketing", + "destKeys": "traits.acceptsMarketing" + }, + + { + "sourceKeys": "orders_count", + "destKeys": "traits.orderCount" + }, + + { + "sourceKeys": "state", + "destKeys": "traits.state" + }, + { + "sourceKeys": "total_spent", + "destKeys": "traits.totalSpent" + }, + { + "sourceKeys": "note", + "destKeys": "traits.note" + }, + { + "sourceKeys": "verified_email", + "destKeys": "traits.verifiedEmail" + }, + { + "sourceKeys": "multipass_identifier", + "destKeys": "traits.multipassIdentifier" + }, + { + "sourceKeys": "tax_exempt", + "destKeys": "traits.taxExempt" + }, + { + "sourceKeys": "tags", + "destKeys": "traits.tags" + }, + { + "sourceKeys": "last_order_name", + "destKeys": "traits.lastOrderName" + }, + { + "sourceKeys": "currency", + "destKeys": "traits.currency" + }, + { + "sourceKeys": "marketing_opt_in_level", + "destKeys": "traits.marketingOptInLevel" + }, + { + "sourceKeys": "tax_exemptions", + "destKeys": "traits.taxExemptions" + }, + { + "sourceKeys": "sms_marketing_consent", + "destKeys": "traits.smsMarketingConsent" + }, + { + "sourceKeys": "admin_graphql_api_id", + "destKeys": "traits.adminGraphqlApiId" + }, + { + "sourceKeys": "accepts_marketing_updated_at", + "destKeys": "traits.acceptsMarketingUpdatedAt" + } +] diff --git a/src/v1/sources/shopify/webhookEventsMapping/lineItemsMapping.json b/src/v1/sources/shopify/webhookEventsMapping/lineItemsMapping.json new file mode 100644 index 0000000000..3bcef331b0 --- /dev/null +++ b/src/v1/sources/shopify/webhookEventsMapping/lineItemsMapping.json @@ -0,0 +1,32 @@ +[ + { + "sourceKeys": "product_id", + "destKey": "product_id", + "metadata": { + "type": "toString" + } + }, + { + "sourceKeys": "sku", + "destKey": "sku" + }, + { + "sourceKeys": "name", + "destKey": "title" + }, + { + "sourceKeys": "price", + "destKey": "price", + "metadata": { + "type": "toNumber" + } + }, + { + "sourceKeys": "vendor", + "destKey": "brand" + }, + { + "sourceKeys": "quantity", + "destKey": "quantity" + } +] diff --git a/src/v1/sources/shopify/webhookEventsMapping/mapping.json b/src/v1/sources/shopify/webhookEventsMapping/mapping.json new file mode 100644 index 0000000000..6c268ef13c --- /dev/null +++ b/src/v1/sources/shopify/webhookEventsMapping/mapping.json @@ -0,0 +1,10 @@ +[ + { + "sourceKeys": "line_items", + "destKeys": "products" + }, + { + "sourceKeys": "id", + "destKeys": "properties.order_id" + } +] diff --git a/src/v1/sources/shopify/webhookEventsMapping/productMapping.json b/src/v1/sources/shopify/webhookEventsMapping/productMapping.json new file mode 100644 index 0000000000..e78ed50dfc --- /dev/null +++ b/src/v1/sources/shopify/webhookEventsMapping/productMapping.json @@ -0,0 +1,24 @@ +[ + { + "sourceKeys": "id", + "destKey": "order_id", + "metadata": { + "type": "toString" + } + }, + { + "sourceKeys": "total_price", + "destKey": "value" + }, + { + "sourceKeys": "total_tax", + "destKey": "tax", + "metadata": { + "type": "toNumber" + } + }, + { + "sourceKeys": "currency", + "destKey": "currency" + } +] diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js index 4a2839103b..b94ec9c3dd 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js @@ -98,11 +98,11 @@ describe('serverSideUtils.js', () => { const result = createPropertiesForEcomEventFromWebhook(message); expect(result).toEqual({ products: [ - { brand: 'Hydrogen Vendor', price: '600.00', product_id: 7234590408818, quantity: 1 }, + { brand: 'Hydrogen Vendor', price: 600.0, product_id: '7234590408818', quantity: 1 }, { brand: 'Hydrogen Vendor', - price: '600.00', - product_id: 7234590408817, + price: 600.0, + product_id: '7234590408817', quantity: 1, title: 'The Collection Snowboard: Nitrogen', }, diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js index 951fa479e4..0b8626cdf1 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -1,9 +1,6 @@ const { isDefinedAndNotNull } = require('@rudderstack/integrations-lib'); const { constructPayload } = require('../../../../v0/util'); -const { - lineItemsMappingJSON, - productMappingJSON, -} = require('../../../../v0/sources/shopify/config'); +const { lineItemsMappingJSON, productMappingJSON } = require('../config'); /** * Returns an array of products from the lineItems array received from the webhook event diff --git a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts index 38f682ac6d..3db2e3ab10 100644 --- a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts +++ b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts @@ -2037,7 +2037,7 @@ export const pixelCheckoutStepsScenarios = [ SHOPIFY: true, }, type: 'track', - event: 'Payment Info Submitted', + event: 'Payment Info Entered', properties: { buyerAcceptsEmailMarketing: false, buyerAcceptsSmsMarketing: false, diff --git a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts index a154ccb890..ccdeccaf91 100644 --- a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts +++ b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts @@ -219,14 +219,14 @@ export const checkoutEventsTestScenarios = [ type: 'track', event: 'Checkout Started', properties: { - order_id: 35550298931313, + order_id: '35550298931313', value: '600.00', - tax: '0.00', + tax: 0, currency: 'USD', products: [ { - product_id: 7234590408817, - price: '600.00', + product_id: '7234590408817', + price: 600.0, brand: 'Hydrogen Vendor', quantity: 1, }, @@ -533,16 +533,16 @@ export const checkoutEventsTestScenarios = [ }, properties: { currency: 'USD', - order_id: 35374569160817, + order_id: '35374569160817', products: [ { brand: 'pixel-testing-rs', - price: '729.95', - product_id: 7234590638193, + price: 729.95, + product_id: '7234590638193', quantity: 1, }, ], - tax: '0.00', + tax: 0, value: '736.85', }, timestamp: '2024-09-17T07:29:02.000Z', @@ -1207,15 +1207,15 @@ export const checkoutEventsTestScenarios = [ type: 'track', event: 'Order Updated', properties: { - order_id: 5778367414385, + order_id: '5778367414385', value: '600.00', - tax: '0.00', + tax: 0, currency: 'USD', products: [ { - product_id: 7234590408817, + product_id: '7234590408817', title: 'The Collection Snowboard: Hydrogen', - price: '600.00', + price: 600, brand: 'Hydrogen Vendor', quantity: 1, }, @@ -1598,15 +1598,15 @@ export const checkoutEventsTestScenarios = [ type: 'track', event: 'Order Created', properties: { - order_id: 5778367414385, + order_id: '5778367414385', value: '600.00', - tax: '0.00', + tax: 0, currency: 'USD', products: [ { - product_id: 7234590408817, + product_id: '7234590408817', title: 'The Collection Snowboard: Hydrogen', - price: '600.00', + price: 600, brand: 'Hydrogen Vendor', quantity: 1, }, From 2bfb88ca0db5ce1ede3e57420bd659c4ebfb9877 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Mon, 23 Dec 2024 20:44:45 +0530 Subject: [PATCH 2/3] chore: server suffix in checkout started webhook event --- src/v1/sources/shopify/config.js | 8 ++++++++ .../shopify/webhookTransformations/serverSideTransform.js | 2 +- .../shopify/webhookTestScenarios/CheckoutEventsTests.ts | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index 4115b6ae94..81f095dbe9 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -35,6 +35,13 @@ const PIXEL_EVENT_MAPPING = { search_submitted: 'Search Submitted', }; +const RUDDER_ECOM_MAP = { + checkouts_create: 'Checkout Started Server', + checkouts_update: 'Checkout Updated', + orders_updated: 'Order Updated', + orders_create: 'Order Created', +}; + const contextualFieldMappingJSON = JSON.parse( fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'contextualFieldMapping.json')), ); @@ -87,6 +94,7 @@ module.exports = { INTEGERATION, PIXEL_EVENT_TOPICS, PIXEL_EVENT_MAPPING, + RUDDER_ECOM_MAP, contextualFieldMappingJSON, cartViewedEventMappingJSON, productListViewedEventMappingJSON, diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js index 292a980a93..f6f3e03336 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js @@ -11,11 +11,11 @@ const { MAPPING_CATEGORIES, IDENTIFY_TOPICS, ECOM_TOPICS, - RUDDER_ECOM_MAP, SUPPORTED_TRACK_EVENTS, SHOPIFY_TRACK_MAP, lineItemsMappingJSON, } = require('../../../../v0/sources/shopify/config'); +const { RUDDER_ECOM_MAP } = require('../config'); const { createPropertiesForEcomEventFromWebhook, getProductsFromLineItems, diff --git a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts index ccdeccaf91..26b18a90a5 100644 --- a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts +++ b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts @@ -217,7 +217,7 @@ export const checkoutEventsTestScenarios = [ SHOPIFY: true, }, type: 'track', - event: 'Checkout Started', + event: 'Checkout Started Server', properties: { order_id: '35550298931313', value: '600.00', From b48828f7ad9574884a63edd81bbcf3d100b3bbf1 Mon Sep 17 00:00:00 2001 From: Yashasvi Bajpai <33063622+yashasvibajpai@users.noreply.github.com> Date: Wed, 25 Dec 2024 23:00:12 +0530 Subject: [PATCH 3/3] chore: remove value from updation webhook events --- .../shopify/webhookTransformations/serverSideTransform.js | 2 +- .../shopify/webhookTransformations/serverSideUtlis.js | 5 ++++- .../shopify/webhookTestScenarios/CheckoutEventsTests.ts | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js index f6f3e03336..d0221f6950 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js @@ -46,7 +46,7 @@ const ecomPayloadBuilder = (event, shopifyTopic) => { message.setEventType(EventType.TRACK); message.setEventName(RUDDER_ECOM_MAP[shopifyTopic]); - const properties = createPropertiesForEcomEventFromWebhook(event); + const properties = createPropertiesForEcomEventFromWebhook(event, shopifyTopic); message.properties = removeUndefinedAndNullValues(properties); // Map Customer details if present const customerDetails = get(event, 'customer'); diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js index 0b8626cdf1..df33d7a347 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -25,12 +25,15 @@ const getProductsFromLineItems = (lineItems, mapping) => { * @param {Object} message * @returns {Object} properties */ -const createPropertiesForEcomEventFromWebhook = (message) => { +const createPropertiesForEcomEventFromWebhook = (message, shopifyTopic) => { const { line_items: lineItems } = message; if (!lineItems || lineItems.length === 0) { return []; } const mappedPayload = constructPayload(message, productMappingJSON); + if (shopifyTopic === 'orders_updated' || shopifyTopic === 'checkouts_update') { + delete mappedPayload.value; + } mappedPayload.products = getProductsFromLineItems(lineItems, lineItemsMappingJSON); return mappedPayload; }; diff --git a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts index 26b18a90a5..673f246455 100644 --- a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts +++ b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts @@ -543,7 +543,6 @@ export const checkoutEventsTestScenarios = [ }, ], tax: 0, - value: '736.85', }, timestamp: '2024-09-17T07:29:02.000Z', traits: { @@ -1208,7 +1207,6 @@ export const checkoutEventsTestScenarios = [ event: 'Order Updated', properties: { order_id: '5778367414385', - value: '600.00', tax: 0, currency: 'USD', products: [