diff --git a/src/index.ts b/src/index.ts index 95fae7f293..b6514dcdea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,7 @@ import { addStatMiddleware, addRequestSizeMiddleware } from './middleware'; import { logProcessInfo } from './util/utils'; import { applicationRoutes } from './routes'; -const { RedisDB } = require('./util/redisConnector'); +const { RedisDB } = require('../src/util/redis/redisConnector'); dotenv.config(); const clusterEnabled = process.env.CLUSTER_ENABLED !== 'false'; diff --git a/src/util/cluster.js b/src/util/cluster.js index e738104335..5012bda324 100644 --- a/src/util/cluster.js +++ b/src/util/cluster.js @@ -2,7 +2,7 @@ const cluster = require('cluster'); const gracefulShutdown = require('http-graceful-shutdown'); const logger = require('../logger'); const { logProcessInfo } = require('./utils'); -const { RedisDB } = require('./redisConnector'); +const { RedisDB } = require('./redis/redisConnector'); const numWorkers = parseInt(process.env.NUM_PROCS || '1', 10); const metricsPort = parseInt(process.env.METRICS_PORT || '9091', 10); diff --git a/src/util/prometheus.js b/src/util/prometheus.js index d3f770649f..a78d1b1bc6 100644 --- a/src/util/prometheus.js +++ b/src/util/prometheus.js @@ -419,6 +419,30 @@ class Prometheus { type: 'counter', labelNames: [], }, + { + name: 'redis_error', + help: 'redis_error', + type: 'counter', + labelNames: ['operation'], + }, + { + name: 'shopify_redis_failures', + help: 'shopify_redis_failures', + type: 'counter', + labelNames: ['type', 'writeKey', 'source'], + }, + { + name: 'shopify_redis_calls', + help: 'shopify_redis_calls', + type: 'counter', + labelNames: ['type', 'writeKey', 'source'], + }, + { + name: 'shopify_redis_no_val', + help: 'shopify_redis_no_val', + type: 'counter', + labelNames: ['event', 'writeKey', 'source'], + }, { name: 'events_to_process', help: 'events_to_process', @@ -436,6 +460,7 @@ class Prometheus { help: 'get_libraries_code', type: 'counter', labelNames: ['libraryVersionId', 'version', 'type', 'success'], + }, // Gauges diff --git a/src/util/redis/redisConnector.js b/src/util/redis/redisConnector.js new file mode 100644 index 0000000000..472835925f --- /dev/null +++ b/src/util/redis/redisConnector.js @@ -0,0 +1,154 @@ +const Redis = require('ioredis'); +const { isDefinedAndNotNull } = require('../../v0/util'); +const { RedisError } = require('../../v0/util/errorTypes'); +const log = require('../../logger'); +const stats = require('../stats'); + +const timeoutPromise = () => new Promise((_, reject) => { + setTimeout( + () => reject(new Error("Timeout while connecting to redis")), + 1000 + ); +}); + +const RedisDB = { + init() { + if (process.env.USE_REDIS_DB && process.env.USE_REDIS_DB !== 'false') { + this.host = process.env.REDIS_HOST || 'localhost'; + this.port = parseInt(process.env.REDIS_PORT, 10) || 6379; + this.password = process.env.REDIS_PASSWORD; + this.userName = process.env.REDIS_USERNAME; + this.maxRetries = parseInt(process.env.REDIS_MAX_RETRIES, 10) || 5; + this.timeAfterRetry = parseInt(process.env.REDIS_TIME_AFTER_RETRY_IN_MS, 10) || 500; + this.client = new Redis({ + host: this.host, + port: this.port, + password: this.password, + username: this.userName, + enableReadyCheck: true, + retryStrategy: (times) => { + if (times <= this.maxRetries) { + return (1 + times) * this.timeAfterRetry; // reconnect after + } + stats.increment("redis_error", { + operation: 'redis_down', + }); + log.error(`Redis is down at ${this.host}:${this.port}`); + return false; // stop retrying + }, + }); + this.client.on('ready', () => { + log.info(`Connected to redis at ${this.host}:${this.port}`); + }); + } + }, + + + async checkRedisConnectionReadyState() { + try { + await this.client.connect(); + } catch (error) { + return new Promise((resolve) => { + this.client.on('ready', () => { + resolve(); + }); + }); + } + return Promise.resolve(); + }, + + /** + * Checks connection with redis and if not connected, tries to connect and throws error if connection request fails + */ + async checkAndConnectConnection() { + if (!this.client || this.client.status === "end") { + this.init(); + } + if (this.client.status !== 'ready') { + await Promise.race([this.checkRedisConnectionReadyState(), timeoutPromise()]); + } + }, + /** + * Used to get value from redis depending on the key and the expected value type + * @param {*} hashKey parent key + * @param {*} isObjExpected false if fetched value can not be json + * @param {*} key key for which value needs to be extracted, required if isObjExpected is true + * @returns value which can be json or string or number + * storage of data in case isObjExpected is true + * hashKey:{ + * key1: {internalKey1:val1}, + * key2: {internalKey2:val2}, + * } + */ + async getVal(hashKey, key, isObjExpected = true) { + try { + await this.checkAndConnectConnection(); // check if redis is connected and if not, connect + let redisVal; + if (isObjExpected === true) { + redisVal = await this.client.hget(hashKey, key); + if (isDefinedAndNotNull(redisVal)) { + try { + return JSON.parse(redisVal); + } catch (e) { + // do nothing + return redisVal; + } + } + return redisVal; + } + return this.client.get(hashKey); + } catch (e) { + stats.increment("redis_error", { + operation: "get" + }); + log.error(`Error getting value from Redis: ${e}`); + throw new RedisError(`Error getting value from Redis: ${e}`); + } + }, + /** + * Used to set value in redis depending on the key and the value type + * @param {*} key key for which value needs to be stored + * @param {*} value to be stored in redis send it in array format [field1, value1, field2, value2] + * if Value is an object + * @param {*} expiryTimeInSec expiry time of data in redis by default 1 hr + * @param {*} isValJson set to false if value is not a json object + * + */ + async setVal(key, value, expiryTimeInSec = 60 * 60) { + try { + await this.checkAndConnectConnection(); // check if redis is connected and if not, connect + if (typeof value === "object") { + const valueToStore = value.map(element => { + if (typeof element === "object") { + return JSON.stringify(element); + } + return element; + }) + await this.client.multi() + .hmset(key, ...valueToStore) + .expire(key, expiryTimeInSec) + .exec(); + } else { + await this.client.multi() + .set(key, value) + .expire(key, expiryTimeInSec) + .exec(); + + } + } catch (e) { + stats.increment("redis_error", { + operation: "set" + }); + log.error(`Error setting value in Redis due ${e}`); + throw new RedisError(`Error setting value in Redis due ${e}`); + } + }, + async disconnect() { + if (process.env.USE_REDIS_DB && process.env.USE_REDIS_DB !== 'false') { + log.info(`Disconnecting from redis at ${this.host}:${this.port}`); + this.client.disconnect(); + } + } +}; + +module.exports = { RedisDB }; diff --git a/src/util/redis/redisConnector.test.js b/src/util/redis/redisConnector.test.js new file mode 100644 index 0000000000..e53bb7f8dd --- /dev/null +++ b/src/util/redis/redisConnector.test.js @@ -0,0 +1,110 @@ +const fs = require("fs"); +const path = require("path"); +const version = "v0"; +const { RedisDB } = require('./redisConnector'); +jest.mock('ioredis', () => require('../../../test/__mocks__/redis')); +const sourcesList = ['shopify'] +const destList = []; +process.env.USE_REDIS_DB = 'true'; + +const timeoutPromise = () => new Promise((resolve, _) => { + setTimeout( + () => resolve(), + 100 + ); +}); + +describe('checkRedisConnectionReadyState', () => { + RedisDB.init(); + it('should resolve if client connects after initial connection error', async () => { + RedisDB.client.end(3); + await Promise.race([RedisDB.checkRedisConnectionReadyState(), timeoutPromise()]); + expect(RedisDB.client.status).toBe('ready'); + }); + it('should resolve if client is already connected', async () => { + await RedisDB.checkRedisConnectionReadyState(); + expect(RedisDB.client.status).toBe('ready'); + }); +}); +describe('checkAndConnectConnection', () => { + it('Status is end', async () => { + RedisDB.client.end(11); + await Promise.race([RedisDB.checkAndConnectConnection(), timeoutPromise()]); + expect(RedisDB.client.status).toBe('ready'); + }); + it('should resolve if client is already connected', async () => { + await RedisDB.checkAndConnectConnection(); + expect(RedisDB.client.status).toBe('ready'); + }); +}); +describe(`Source Tests`, () => { + sourcesList.forEach((source) => { + const testDataFile = fs.readFileSync( + path.resolve(__dirname, `./testData/${source}_source.json`) + ); + const data = JSON.parse(testDataFile); + const transformer = require(`../../${version}/sources/${source}/transform`); + + data.forEach((dataPoint, index) => { + it(`${index}. ${source} - ${dataPoint.description}`, async () => { + try { + const output = await transformer.process(dataPoint.input); + expect(output).toEqual(dataPoint.output); + } catch (error) { + expect(error.message).toEqual(dataPoint.output.error); + } + }); + }); + }) +}); + +describe(`Redis Class Get Tests`, () => { + const testDataFile = fs.readFileSync( + path.resolve(__dirname, `./testData/redisConnector.json`) + ); + const data = JSON.parse(testDataFile); + data.forEach((dataPoint, index) => { + it(`${index}. Redis Get- ${dataPoint.description}`, async () => { + try { + const output = await RedisDB.getVal(dataPoint.input.value, isObjExpected = false); + expect(output).toEqual(dataPoint.output); + } catch (error) { + expect(error.message).toEqual(dataPoint.output.error); + } + }); + }); + it(`Redis Get- Nothing Found in redis - return null`, async () => { + const dataPoint = { + input: { + value: "not_in_redis", + }, + output: { + value: null + } + }; + const output = await RedisDB.getVal(dataPoint.input.value, "key1"); + expect(output).toEqual(dataPoint.output.value); + }); +}); + +describe(`Redis Class Set Test`, () => { + it(`Redis Set Fail Case Test`, async () => { + try { + await RedisDB.setVal("error", "test"); + } catch (error) { + expect(error.message).toEqual("Error setting value in Redis due Error: Connection is Closed"); + } + }); + it(`Redis Set Fail Case Test`, async () => { + const result = "OK" + await RedisDB.setVal("Key", "test"); + expect(result).toEqual("OK"); + }); +}); +describe(`Redis Disconnect`, () => { + it(`Redis Disconnect Test`, async () => { + const result = "OK" + await RedisDB.disconnect(); + expect(result).toEqual("OK"); + }); +}); diff --git a/test/__tests__/data/redis/redisConnector.json b/src/util/redis/testData/redisConnector.json similarity index 56% rename from test/__tests__/data/redis/redisConnector.json rename to src/util/redis/testData/redisConnector.json index 48cc0069cd..5a6197cabc 100644 --- a/test/__tests__/data/redis/redisConnector.json +++ b/src/util/redis/testData/redisConnector.json @@ -7,12 +7,5 @@ "output": { "error": "Error getting value from Redis: Error: Connection is Closed" } - }, - { - "description": "Get Value Successfull", - "input": { - "value": "redis_test_get" - }, - "output": "\"redis_test_get_value\"" } -] +] \ No newline at end of file diff --git a/src/util/redis/testData/shopify_source.json b/src/util/redis/testData/shopify_source.json new file mode 100644 index 0000000000..a267b38745 --- /dev/null +++ b/src/util/redis/testData/shopify_source.json @@ -0,0 +1,1022 @@ +[ + { + "description": "Track Call -> duplicate carts_update ", + "input": { + "id": "shopify_test3", + "query_parameters": { + "topic": [ + "carts_update" + ] + }, + "token": "shopify_test3", + "line_items": [], + "note": null, + "updated_at": "2023-02-10T12:16:07.251Z", + "created_at": "2023-02-10T12:16:04.402Z" + }, + "output": { + "outputToSource": { + "body": "T0s=", + "contentType": "text/plain" + }, + "statusCode": 200 + } + }, + { + "description": "Track Call -> orders_delete with invalid cartToken", + "input": { + "id": "shopify_test3", + "query_parameters": { + "topic": [ + "orders_delete" + ] + }, + "line_items": [], + "note": null, + "updated_at": "2023-02-10T12:16:07.251Z", + "created_at": "2023-02-10T12:05:04.402Z" + }, + "output": { + "context": { + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" + }, + "integration": { + "name": "SHOPIFY" + }, + "topic": "orders_delete" + }, + "event": "Order Deleted", + "integrations": { + "SHOPIFY": true + }, + "type": "track", + "userId": "shopify-admin", + "properties": { + "created_at": "2023-02-10T12:05:04.402Z", + "id": "shopify_test3", + "note": null, + "products": [], + "updated_at": "2023-02-10T12:16:07.251Z" + } + } + }, + { + "description": "Track Call -> checkouts_delete with invalid cartToken", + "input": { + "id": "shopify_test3", + "query_parameters": { + "topic": [ + "checkouts_delete" + ] + }, + "line_items": [], + "note": null, + "updated_at": "2023-02-10T12:16:07.251Z", + "created_at": "2023-02-10T12:05:04.402Z" + }, + "output": { + "context": { + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" + }, + "integration": { + "name": "SHOPIFY" + }, + "topic": "checkouts_delete" + }, + "event": "Checkout Deleted", + "integrations": { + "SHOPIFY": true + }, + "type": "track", + "userId": "shopify-admin", + "properties": { + "created_at": "2023-02-10T12:05:04.402Z", + "id": "shopify_test3", + "note": null, + "products": [], + "updated_at": "2023-02-10T12:16:07.251Z" + } + } + }, + { + "description": "Track Call -> carts_update", + "input": { + "user_id": "rudder01", + "id": "shopify_test_cart", + "query_parameters": { + "topic": [ + "carts_update" + ] + }, + "token": "shopify_test_cart", + "email": "test@rudderstack.com", + "line_items": [ + { + "id": 44323300999443, + "properties": null, + "quantity": 1, + "variant_id": 44323300999443, + "key": "44323300999443:70b21df78d403673a8b5dbafd62f0559", + "discounted_price": "30.00", + "discounts": [], + "gift_card": false, + "grams": 0, + "line_price": "30.00", + "original_line_price": "30.00", + "original_price": "30.00", + "price": "30.00", + "product_id": 8100575674643, + "sku": "", + "taxable": true, + "title": "Shirt 2 - LARGE", + "total_discount": "0.00", + "vendor": "testAnant", + "discounted_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "original_line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "total_discount_set": { + "shop_money": { + "amount": "0.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "0.0", + "currency_code": "GBP" + } + } + } + ], + "note": null, + "updated_at": "2023-02-10T12:16:07.251Z", + "created_at": "2023-02-10T12:05:04.402Z" + }, + "output": { + "userId": "rudder01", + "anonymousId": "anon_shopify_test1", + "context": { + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" + }, + "integration": { + "name": "SHOPIFY" + }, + "topic": "carts_update" + }, + "event": "Cart Update", + "integrations": { + "SHOPIFY": true + }, + "traits": { + "email": "test@rudderstack.com" + }, + "type": "track", + "properties": { + "note": null, + "created_at": "2023-02-10T12:05:04.402Z", + "email": "test@rudderstack.com", + "id": "shopify_test_cart", + "products": [ + { + "id": 44323300999443, + "properties": null, + "quantity": 1, + "variant": "44323300999443 ", + "key": "44323300999443:70b21df78d403673a8b5dbafd62f0559", + "discounted_price": "30.00", + "discounts": [], + "gift_card": false, + "grams": 0, + "line_price": "30.00", + "original_line_price": "30.00", + "original_price": "30.00", + "price": "30.00", + "product_id": 8100575674643, + "taxable": true, + "title": "Shirt 2 - LARGE", + "total_discount": "0.00", + "brand": "testAnant", + "discounted_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "original_line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "total_discount_set": { + "shop_money": { + "amount": "0.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "0.0", + "currency_code": "GBP" + } + } + } + ], + "user_id": "rudder01", + "token": "shopify_test_cart", + "updated_at": "2023-02-10T12:16:07.251Z" + } + } + }, + { + "description": "Track Call -> orders_updated with empty line_items", + "input": { + "id": "shopify_test2", + "query_parameters": { + "topic": [ + "orders_updated" + ] + }, + "shipping_address": "abc", + "billing_address": "abc", + "customer": { + "first_name": "Test", + "last_name": "Person" + }, + "cart_token": null, + "checkout_id": 36601802719507, + "checkout_token": "checkout token", + "client_details": { + "accept_language": null, + "browser_height": null, + "browser_ip": "122.161.73.113", + "user_agent": "Mozilla/5.0 User Agent" + }, + "line_items": [], + "note": null, + "updated_at": "2023-02-10T12:16:07.251Z", + "created_at": "2023-02-10T12:05:04.402Z" + }, + "output": { + "userId": "shopify-admin", + "context": { + "cart_token": null, + "checkout_token": "checkout token", + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" + }, + "integration": { + "name": "SHOPIFY" + }, + "topic": "orders_updated" + }, + "event": "Order Updated", + "integrations": { + "SHOPIFY": true + }, + "type": "track", + "properties": { + "checkout_id": 36601802719507, + "checkout_token": "checkout token", + "client_details": { + "accept_language": null, + "browser_height": null, + "browser_ip": "122.161.73.113", + "user_agent": "Mozilla/5.0 User Agent" + }, + "order_id": "shopify_test2", + "created_at": "2023-02-10T12:05:04.402Z", + "products": [], + "updated_at": "2023-02-10T12:16:07.251Z" + }, + "traits": { + "shippingAddress": "abc", + "billingAddress": "abc", + "firstName": "Test", + "lastName": "Person" + }, + "timestamp": "2023-02-10T12:16:07.251Z" + } + }, + { + "description": "Track Call -> fullfillments_create", + "input": { + "query_parameters": { + "topic": [ + "fulfillments_create" + ] + }, + "order_id": "random", + "status": "success", + "created_at": "2023-02-10T07:44:06-05:00", + "service": "manual", + "updated_at": "2023-02-10T07:44:06-05:00", + "tracking_company": null, + "shipment_status": null, + "location_id": 77735330067, + "origin_address": null, + "destination": null, + "line_items": [ + { + "variant_id": "variantId", + "title": "bitter cloud", + "quantity": 1, + "sku": "", + "variant_title": null, + "vendor": "testAnant", + "fulfillment_service": "manual", + "product_id": 8100634689811, + "requires_shipping": true, + "taxable": true, + "gift_card": false, + "name": "bitter cloud", + "variant_inventory_management": null, + "properties": [], + "product_exists": true, + "fulfillable_quantity": 0, + "grams": 0, + "price": "9.54", + "total_discount": "0.00", + "fulfillment_status": "fulfilled", + "price_set": { + "shop_money": { + "amount": "9.54", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "9.54", + "currency_code": "GBP" + } + }, + "total_discount_set": { + "shop_money": { + "amount": "0.00", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "0.00", + "currency_code": "GBP" + } + }, + "discount_allocations": [], + "duties": [], + "shopify-admin_graphql_api_id": "gid://shopify/LineItem/13729348059411", + "tax_lines": [] + } + ], + "tracking_number": null, + "tracking_numbers": [], + "tracking_url": null, + "tracking_urls": [], + "receipt": {}, + "name": "#1001.1", + "shopify-admin_graphql_api_id": "gid://shopify/Fulfillment/4655820210451" + }, + "output": { + "userId": "shopify-admin", + "context": { + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" + }, + "integration": { + "name": "SHOPIFY" + }, + "topic": "fulfillments_create" + }, + "event": "Fulfillments Create", + "integrations": { + "SHOPIFY": true + }, + "type": "track", + "properties": { + "shopify-admin_graphql_api_id": "gid://shopify/Fulfillment/4655820210451", + "created_at": "2023-02-10T07:44:06-05:00", + "destination": null, + "location_id": 77735330067, + "name": "#1001.1", + "order_id": "random", + "origin_address": null, + "products": [ + { + "shopify-admin_graphql_api_id": "gid://shopify/LineItem/13729348059411", + "quantity": 1, + "product_exists": true, + "title": "bitter cloud", + "product_id": 8100634689811, + "properties": [], + "requires_shipping": true, + "tax_lines": [], + "variant": "variantId ", + "variant_inventory_management": null, + "price": "9.54", + "taxable": true, + "total_discount": "0.00", + "brand": "testAnant", + "fulfillable_quantity": 0, + "fulfillment_service": "manual", + "fulfillment_status": "fulfilled", + "gift_card": false, + "grams": 0, + "discount_allocations": [], + "duties": [], + "price_set": { + "shop_money": { + "amount": "9.54", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "9.54", + "currency_code": "GBP" + } + }, + "total_discount_set": { + "shop_money": { + "amount": "0.00", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "0.00", + "currency_code": "GBP" + } + } + } + ], + "receipt": {}, + "service": "manual", + "shipment_status": null, + "status": "success", + "tracking_company": null, + "tracking_number": null, + "tracking_numbers": [], + "tracking_url": null, + "tracking_urls": [], + "updated_at": "2023-02-10T07:44:06-05:00" + } + } + }, + { + "description": "Track Call -> checkouts_update ", + "input": { + "id": "shopify_test2", + "query_parameters": { + "topic": [ + "checkouts_update" + ] + }, + "token": "shopify_test2", + "cart_token": "shopify_test2", + "line_items": [ + { + "id": 44323300999443, + "token": "shopify_test2", + "properties": null, + "quantity": 1, + "variant_id": 44323300999443, + "key": "44323300999443:ky", + "discounted_price": "30.00", + "discounts": [], + "gift_card": false, + "grams": 0, + "line_price": "30.00", + "original_line_price": "30.00", + "original_price": "30.00", + "price": "30.00", + "product_id": 8100575674643, + "sku": "", + "taxable": true, + "title": "Shirt 2 - LARGE", + "total_discount": "0.00", + "vendor": "testAnant", + "discounted_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "original_line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "total_discount_set": { + "shop_money": { + "amount": "0.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "0.0", + "currency_code": "GBP" + } + } + } + ], + "note": null, + "updated_at": "2023-02-10T12:16:07.251Z", + "created_at": "2023-02-10T12:05:04.402Z" + }, + "output": { + "anonymousId": "anon_shopify_test2", + "context": { + "cart_token": "shopify_test2", + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" + }, + "integration": { + "name": "SHOPIFY" + }, + "topic": "checkouts_update" + }, + "event": "Checkout Updated", + "integrations": { + "SHOPIFY": true + }, + "type": "track", + "properties": { + "created_at": "2023-02-10T12:05:04.402Z", + "cart_token": "shopify_test2", + "order_id": "shopify_test2", + "products": [ + { + "id": 44323300999443, + "properties": null, + "quantity": 1, + "variant": "44323300999443 ", + "key": "44323300999443:ky", + "discounted_price": "30.00", + "discounts": [], + "gift_card": false, + "grams": 0, + "line_price": "30.00", + "original_line_price": "30.00", + "original_price": "30.00", + "price": "30.00", + "product_id": 8100575674643, + "taxable": true, + "token": "shopify_test2", + "title": "Shirt 2 - LARGE", + "total_discount": "0.00", + "brand": "testAnant", + "discounted_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "original_line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "total_discount_set": { + "shop_money": { + "amount": "0.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "0.0", + "currency_code": "GBP" + } + } + } + ], + "token": "shopify_test2", + "updated_at": "2023-02-10T12:16:07.251Z" + }, + "timestamp": "2023-02-10T12:16:07.251Z" + } + }, + { + "description": "Track Call -> checkouts_update with null cartToken", + "input": { + "id": "shopify_test2", + "query_parameters": { + "topic": [ + "checkouts_update" + ] + }, + "cart_token": null, + "line_items": [ + { + "id": 44323300999443, + "properties": null, + "quantity": 1, + "variant_id": 44323300999443, + "key": "44323300999443:ky", + "discounted_price": "30.00", + "discounts": [], + "gift_card": false, + "grams": 0, + "line_price": "30.00", + "original_line_price": "30.00", + "original_price": "30.00", + "price": "30.00", + "product_id": 8100575674643, + "sku": "", + "taxable": true, + "title": "Shirt 2 - LARGE", + "total_discount": "0.00", + "vendor": "testAnant", + "discounted_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "original_line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "total_discount_set": { + "shop_money": { + "amount": "0.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "0.0", + "currency_code": "GBP" + } + } + } + ], + "note": null, + "updated_at": "2023-02-10T12:16:07.251Z", + "created_at": "2023-02-10T12:05:04.402Z" + }, + "output": { + "userId": "shopify-admin", + "context": { + "cart_token": null, + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" + }, + "integration": { + "name": "SHOPIFY" + }, + "topic": "checkouts_update" + }, + "event": "Checkout Updated", + "integrations": { + "SHOPIFY": true + }, + "type": "track", + "properties": { + "order_id": "shopify_test2", + "created_at": "2023-02-10T12:05:04.402Z", + "products": [ + { + "id": 44323300999443, + "properties": null, + "quantity": 1, + "variant": "44323300999443 ", + "key": "44323300999443:ky", + "discounted_price": "30.00", + "discounts": [], + "gift_card": false, + "grams": 0, + "line_price": "30.00", + "original_line_price": "30.00", + "original_price": "30.00", + "price": "30.00", + "product_id": 8100575674643, + "taxable": true, + "title": "Shirt 2 - LARGE", + "total_discount": "0.00", + "brand": "testAnant", + "discounted_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "original_line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "total_discount_set": { + "shop_money": { + "amount": "0.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "0.0", + "currency_code": "GBP" + } + } + } + ], + "updated_at": "2023-02-10T12:16:07.251Z" + }, + "timestamp": "2023-02-10T12:16:07.251Z" + } + }, + { + "description": "Track Call -> carts_update with invalid cartToken", + "input": { + "id": "shopify_test4", + "query_parameters": { + "topic": [ + "carts_update" + ] + }, + "token": "shopify_test4", + "line_items": [ + { + "id": 44323300999443, + "properties": null, + "quantity": 1, + "variant_id": 44323300999443, + "key": "44323300999443:70b21df78d403673a8b5dbafd62f0559", + "discounted_price": "30.00", + "discounts": [], + "gift_card": false, + "grams": 0, + "line_price": "30.00", + "original_line_price": "30.00", + "original_price": "30.00", + "price": "30.00", + "product_id": 8100575674643, + "sku": "", + "taxable": true, + "title": "Shirt 2 - LARGE", + "total_discount": "0.00", + "vendor": "testAnant", + "discounted_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "original_line_price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "price_set": { + "shop_money": { + "amount": "30.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "30.0", + "currency_code": "GBP" + } + }, + "total_discount_set": { + "shop_money": { + "amount": "0.0", + "currency_code": "GBP" + }, + "presentment_money": { + "amount": "0.0", + "currency_code": "GBP" + } + } + } + ], + "note": null, + "updated_at": "2023-02-10T12:16:07.251Z", + "created_at": "2023-02-10T12:05:04.402Z" + }, + "output": { + "outputToSource": { + "body": "T0s=", + "contentType": "text/plain" + }, + "statusCode": 200 + } + }, + { + "description": "Rudder Identifier Event", + "input": { + "event": "rudderIdentifier", + "anonymousId": "b9993cc5-9e60-4e69-be0e-4e38c228314b", + "cartToken": "shopify_test1", + "query_parameters": { + "writeKey": [ + "Shopify Write Key" + ] + }, + "cart": { + "token": "token", + "id": "id", + "updated_at": "2023-02-10T07:44:06-05:00", + "line_items": [] + } + }, + "output": { + "outputToSource": { + "body": "T0s=", + "contentType": "text/plain" + }, + "statusCode": 200 + } + } +] \ No newline at end of file diff --git a/src/util/redisConnector.js b/src/util/redisConnector.js deleted file mode 100644 index 180d750854..0000000000 --- a/src/util/redisConnector.js +++ /dev/null @@ -1,112 +0,0 @@ -const Redis = require('ioredis'); -const { RedisError } = require('../v0/util/errorTypes'); -const log = require('../logger'); -const stats = require('./stats'); - -const timeoutPromise = new Promise((resolve) => { - setTimeout(() => resolve(), 50); -}); - -const RedisDB = { - init() { - if (process.env.USE_REDIS_DB && process.env.USE_REDIS_DB !== 'false') { - this.host = process.env.REDIS_HOST || 'localhost'; - this.port = parseInt(process.env.REDIS_PORT, 10) || 6379; - this.password = process.env.REDIS_PASSWORD; - this.userName = process.env.REDIS_USERNAME; - this.maxRetries = parseInt(process.env.REDIS_MAX_RETRIES || 30, 10); - this.timeAfterRetry = parseInt(process.env.REDIS_TIME_AFTER_RETRY_IN_MS || 10, 10); - this.client = new Redis({ - host: this.host, - port: this.port, - password: this.password, - username: this.userName, - enableReadyCheck: true, - retryStrategy: (times) => { - if (times <= this.maxRetries) { - return 10 + times * this.timeAfterRetry; - } - log.error(`Redis is down at ${this.host}:${this.port}`); - return false; // stop retrying - }, - }); - this.client.on('ready', () => { - stats.increment('redis_ready', { - timestamp: Date.now(), - }); - log.info(`Connected to redis at ${this.host}:${this.port}`); - }); - } - }, - /** - * Checks connection with redis and if not connected, tries to connect and throws error if connection request fails - */ - async checkAndConnectConnection() { - if (!this.client) { - this.init(); - } else if (this.client.status !== 'ready') { - await Promise.race([this.client.connect(), timeoutPromise]); - } - }, - /** - * Used to get value from redis depending on the key and the expected value type - * @param {*} key key for which value needs to be extracted - * @param {*} isJsonExpected false if fetched value can not be json - * @returns value which can be json or string or number - * - */ - async getVal(key, isJsonExpected = true) { - try { - await this.checkAndConnectConnection(); // check if redis is connected and if not, connect - const value = await this.client.get(key); - if (value) { - const bytes = Buffer.byteLength(value, 'utf-8'); - stats.gauge('redis_get_val_size', bytes, { - timestamp: Date.now(), - }); - } - return isJsonExpected ? JSON.parse(value) : value; - } catch (e) { - stats.increment('redis_get_val_error', { - error: e, - timestamp: Date.now(), - }); - throw new RedisError(`Error getting value from Redis: ${e}`); - } - }, - /** - * Used to set value in redis depending on the key and the value type - * @param {*} key key for which value needs to be stored - * @param {*} value value to be stored in redis - * @param {*} isValJson set to false if value is not a json object - */ - - async setVal(key, value, isValJson = true) { - const dataExpiry = 60 * 60; // 1 hour - try { - await this.checkAndConnectConnection(); // check if redis is connected and if not, connect - const valueToStore = isValJson ? JSON.stringify(value) : value; - const bytes = Buffer.byteLength(valueToStore, 'utf-8'); - await this.client.setex(key, dataExpiry, valueToStore); - stats.gauge('redis_set_val_size', bytes, { - timestamp: Date.now(), - }); - } catch (e) { - stats.increment('redis_set_val_error', { - error: e, - timestamp: Date.now(), - }); - throw new RedisError(`Error setting value in Redis due ${e}`); - } - }, - async disconnect() { - if (process.env.USE_REDIS_DB && process.env.USE_REDIS_DB !== 'false') { - stats.increment('redis_graceful_shutdown', { - timestamp: Date.now(), - }); - this.client.quit(); - } - }, -}; - -module.exports = { RedisDB }; diff --git a/src/v0/sources/shopify/config.js b/src/v0/sources/shopify/config.js index 23fc562f0e..b541db0468 100644 --- a/src/v0/sources/shopify/config.js +++ b/src/v0/sources/shopify/config.js @@ -21,10 +21,14 @@ const RUDDER_ECOM_MAP = { orders_updated: 'Order Updated', orders_create: 'Order Created', }; +const SHOPIFY_ADMIN_ONLY_EVENTS = [ + 'Order Deleted', + 'Fulfillments Create', + 'Fulfillments Update', +]; const SHOPIFY_TRACK_MAP = { checkouts_delete: 'Checkout Deleted', - carts_create: 'Cart Create', carts_update: 'Cart Update', customers_enable: 'Customer Enabled', customers_disable: 'Customer Disabled', @@ -90,7 +94,6 @@ const SUPPORTED_TRACK_EVENTS = [ 'checkouts_update', 'customers_disable', 'customers_enable', - 'carts_create', 'carts_update', 'fulfillments_create', 'fulfillments_update', @@ -102,8 +105,8 @@ const SUPPORTED_TRACK_EVENTS = [ 'orders_paid', 'orders_partially_fullfilled', ]; -const timeDifferenceForCartEvents = 10000; // in micro seconds as we will be compairing it in timestamp const useRedisDatabase = process.env.USE_REDIS_DB === 'true' || false; + module.exports = { ECOM_TOPICS, IDENTIFY_TOPICS, @@ -116,6 +119,6 @@ module.exports = { PRODUCT_MAPPING_EXCLUSION_FIELDS, SUPPORTED_TRACK_EVENTS, SHOPIFY_TRACK_MAP, - timeDifferenceForCartEvents, useRedisDatabase, + SHOPIFY_ADMIN_ONLY_EVENTS }; diff --git a/src/v0/sources/shopify/shopify.util.test.js b/src/v0/sources/shopify/shopify.util.test.js new file mode 100644 index 0000000000..8bca7bb3a8 --- /dev/null +++ b/src/v0/sources/shopify/shopify.util.test.js @@ -0,0 +1,216 @@ +const { getShopifyTopic, + getAnonymousIdFromDb, + getAnonymousId, + checkAndUpdateCartItems } = require('./util'); + +jest.mock('ioredis', () => require('../../../../test/__mocks__/redis')); +process.env.USE_REDIS_DB = 'true'; +describe('Shopify Utils Test', () => { + describe('Fetching Shopify Topic Test Cases', () => { + it('Invalid Topic Test', () => { + const input = { + query_parameters: { + } + }; + const expectedOutput = { + error: "Invalid topic in query_parameters" + } + try { + getShopifyTopic(input); + } catch (error) { + expect(error.message).toEqual(expectedOutput.error); + } + }); + + it('No Topic Found Test', () => { + const input = { + query_parameters: { + topic: [], + } + }; + const expectedOutput = { + error: 'Topic not found', + }; + try { + getShopifyTopic(input); + } catch (error) { + expect(error.message).toEqual(expectedOutput.error); + } + }); + + it('Successfully fetched topic Test', () => { + const input = { + query_parameters: { + topic: [''], + } + }; + const expectedOutput = ''; + const actualOutput = getShopifyTopic(input); + expect(actualOutput).toEqual(expectedOutput); + }); + + it('Empty Query Params Test', () => { + const input = { + randomKey: 'randomValue', + }; + const expectedOutput = { + error: 'Query_parameters is missing', + }; + try { + getShopifyTopic(input); + } catch (error) { + expect(error.message).toEqual(expectedOutput.error); + } + }); + }); + + describe('set AnonymousId without using Redis Test Cases', () => { + it('Properties containing cartToken', () => { + const input = { + event: 'Order Updated', + properties: { + cart_token: '123', + } + }; + const expectedOutput = 'b9b6607d-6974-594f-8e99-ac3de71c4d89'; + const output = getAnonymousId(input); + expect(output).toEqual(expectedOutput); + }); + + it('Properties contain id for cart event', () => { + const input = { + event: 'Cart Update', + properties: { + id: '123', + } + }; + + const expectedOutput = 'b9b6607d-6974-594f-8e99-ac3de71c4d89'; + const output = getAnonymousId(input); + expect(output).toEqual(expectedOutput); + }); + + it('Customer event -> random AnonymousId', () => { + const input = { + event: 'Customer Enabled', + properties: { + } + }; + const output = getAnonymousId(input); + expect(output).toEqual(output); // since it will be random + }); + + it('Order Delete -> No anonymousId is there', () => { + const input = { + event: 'Order Deleted', + properties: { + order_id: 'Order_ID' + } + }; + const expectedOutput = null; + const output = getAnonymousId(input); + expect(output).toEqual(expectedOutput); + }); + }); + + describe('set AnonymousId with Redis Test Cases', () => { + it('Properties containing cartToken but due some redisError it failed', async () => { + const input = { + event: 'Order Paid', + properties: { + cart_token: 'shopify_test2', + } + }; + const expectedOutput = 'bcaf0473-fb11-562f-80a1-c83a35f053bc' + const output = await getAnonymousIdFromDb(input); + expect(output).toEqual(expectedOutput); + }); + + it('Properties containing cartToken', async () => { + const input = { + event: 'Order Paid', + properties: { + cart_token: 'shopify_test2', + } + }; + const expectedOutput = 'anon_shopify_test2' + const output = await getAnonymousIdFromDb(input); + expect(output).toEqual(expectedOutput); + }); + + it('Properties contain id for cart event', async () => { + const input = { + event: 'Cart Update', + properties: { + id: 'shopify_test2', + } + }; + + const expectedOutput = 'anon_shopify_test2'; + const output = await getAnonymousIdFromDb(input); + expect(output).toEqual(expectedOutput); + }); + + it('Properties contain id for cart event but it is not present in DB', async () => { + const input = { + event: 'Cart Update', + properties: { + id: 'unstored_id', + } + }; + + const expectedOutput = '281a3e25-e603-5870-9cda-281c22940970'; + const output = await getAnonymousIdFromDb(input); + expect(output).toEqual(expectedOutput); + }); + }); + describe('Check for valid cart update event test cases', () => { + it('Event containing token and nothing is retreived from redis', async () => { + const input = { + token: "token_not_in_redis", + line_items: [ + { + prod_id: "prod_1", + quantity: 1, + } + ] + }; + const expectedOutput = false + const output = await checkAndUpdateCartItems(input); + expect(output).toEqual(expectedOutput); + }); + + it('Event contain id for cart_update event and isValid', async () => { + const input = { + id: "shopify_test2", + line_items: [ + { + prod_id: "prod_1", + quantity: 1, + } + ] + }; + + const expectedOutput = true; + const output = await checkAndUpdateCartItems(input); + expect(output).toEqual(expectedOutput); + }); + + it('Event contain id for cart_update event and isInValid', async () => { + const input = { + id: "shopify_test_duplicate_cart", + line_items: [ + { + prod_id: "prod_1", + quantity: 1, + } + ] + }; + + const expectedOutput = false; + const output = await checkAndUpdateCartItems(input); + expect(output).toEqual(expectedOutput); + }); + }); + +}); diff --git a/src/v0/sources/shopify/transform.js b/src/v0/sources/shopify/transform.js index 44e4519ff9..b19d7a8ac7 100644 --- a/src/v0/sources/shopify/transform.js +++ b/src/v0/sources/shopify/transform.js @@ -6,12 +6,13 @@ const { createPropertiesForEcomEvent, getProductsListFromLineItems, extractEmailFromPayload, - setAnonymousIdorUserIdFromDb, - setAnonymousId, - // checkForValidRecord, + getAnonymousIdFromDb, + getAnonymousId, + checkAndUpdateCartItems, + getHashLineItems } = require('./util'); -const { RedisDB } = require('../../../util/redisConnector'); -const { removeUndefinedAndNullValues } = require('../../util'); +const { RedisDB } = require('../../../util/redis/redisConnector'); +const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../util'); const Message = require('../message'); const { EventType } = require('../../../constants'); const { @@ -22,7 +23,7 @@ const { RUDDER_ECOM_MAP, SUPPORTED_TRACK_EVENTS, SHOPIFY_TRACK_MAP, - useRedisDatabase, + useRedisDatabase } = require('./config'); const { TransformationError } = require('../../util/errorTypes'); @@ -130,6 +131,21 @@ const processEvent = async (inputEvent, metricMetadata) => { case ECOM_TOPICS.CHECKOUTS_UPDATE: message = ecomPayloadBuilder(event, shopifyTopic); break; + case "carts_update": + if (useRedisDatabase) { + const isValidEvent = await checkAndUpdateCartItems(inputEvent, metricMetadata); + if (!isValidEvent) { + return { + outputToSource: { + body: Buffer.from('OK').toString('base64'), + contentType: 'text/plain', + }, + statusCode: 200, + } + } + } + message = trackPayloadBuilder(event, shopifyTopic); + break; default: if (!SUPPORTED_TRACK_EVENTS.includes(shopifyTopic)) { throw new TransformationError(`event type ${shopifyTopic} not supported`); @@ -148,10 +164,16 @@ const processEvent = async (inputEvent, metricMetadata) => { } } if (message.type !== EventType.IDENTIFY) { + let anonymousId; if (useRedisDatabase) { - await setAnonymousIdorUserIdFromDb(message, metricMetadata); + anonymousId = await getAnonymousIdFromDb(message, metricMetadata); } else { - setAnonymousId(message); + anonymousId = getAnonymousId(message); + } + if (isDefinedAndNotNull(anonymousId)) { + message.setProperty('anonymousId', anonymousId); + } else if (!message.userId) { + message.setProperty('userId', 'shopify-admin'); } } message.setProperty(`integrations.${INTEGERATION}`, true); @@ -172,14 +194,19 @@ const processEvent = async (inputEvent, metricMetadata) => { const isIdentifierEvent = (event) => event?.event === 'rudderIdentifier'; const processIdentifierEvent = async (event, metricMetadata) => { if (useRedisDatabase) { - const setStartTime = Date.now(); - await RedisDB.setVal(`${event.cartToken}`, { anonymousId: event.anonymousId }); - stats.timing('redis_set_latency', setStartTime, { - ...metricMetadata, - }); - stats.increment('shopify_redis_set_anonymousId', { + const lineItemshash = getHashLineItems(event.cart) + const value = ["anonymousId", event.anonymousId, "itemsHash", lineItemshash]; + try { + await RedisDB.setVal(`${event.cartToken}`, value); + } catch (e) { + stats.increment('shopify_redis_failures', { + type: "set", + ...metricMetadata, + }); + } + stats.increment('shopify_redis_calls', { + type: 'set', ...metricMetadata, - timestamp: Date.now(), }); } const result = { diff --git a/src/v0/sources/shopify/util.js b/src/v0/sources/shopify/util.js index 57cfb8856b..3a48095128 100644 --- a/src/v0/sources/shopify/util.js +++ b/src/v0/sources/shopify/util.js @@ -1,24 +1,18 @@ /* eslint-disable camelcase */ +const { v5 } = require('uuid'); const sha256 = require('sha256'); const stats = require('../../../util/stats'); -const { - constructPayload, - extractCustomFields, - flattenJson, - generateUUID, - isDefinedAndNotNull, -} = require('../../util'); -const { RedisDB } = require('../../../util/redisConnector'); +const { constructPayload, extractCustomFields, flattenJson, generateUUID, isDefinedAndNotNull } = require('../../util'); +const { RedisDB } = require('../../../util/redis/redisConnector'); const logger = require('../../../logger'); const { lineItemsMappingJSON, productMappingJSON, LINE_ITEM_EXCLUSION_FIELDS, PRODUCT_MAPPING_EXCLUSION_FIELDS, - RUDDER_ECOM_MAP, SHOPIFY_TRACK_MAP, + SHOPIFY_ADMIN_ONLY_EVENTS, } = require('./config'); -// 30 mins const { TransformationError } = require('../../util/errorTypes'); /** @@ -43,7 +37,12 @@ const getShopifyTopic = (event) => { } return topic[0]; }; - +const getHashLineItems = (cart) => { + if (cart && cart?.line_items && cart.line_items.length > 0) { + return sha256(JSON.stringify(cart.line_items)); + } + return "EMPTY"; +}; const getVariantString = (lineItem) => { const { variant_id, variant_price, variant_title } = lineItem; return `${variant_id || ''} ${variant_price || ''} ${variant_title || ''}`; @@ -85,46 +84,25 @@ const extractEmailFromPayload = (event) => { }); return email; }; + +const getCartToken = (message) => { + const { event } = message; + if (event === SHOPIFY_TRACK_MAP.carts_update) { + return message.properties?.id || message.properties?.token; + } + return message.properties?.cart_token || null; +} // Hash the id and use it as anonymousId (limiting 256 -> 36 chars) -const setAnonymousId = (message) => { - switch (message.event) { - // These events are fired from admin dashabord and hence we are setting userId as "ADMIN" - case SHOPIFY_TRACK_MAP.orders_delete: - case SHOPIFY_TRACK_MAP.fulfillments_create: - case SHOPIFY_TRACK_MAP.fulfillments_update: - if (!message.userId) { - message.setProperty('userId', 'shopify-admin'); - } - return; - case SHOPIFY_TRACK_MAP.carts_create: - case SHOPIFY_TRACK_MAP.carts_update: - message.setProperty( - 'anonymousId', - message.properties?.id - ? sha256(message.properties.id).toString().substring(0, 36) - : generateUUID(), - ); - break; - case SHOPIFY_TRACK_MAP.orders_edited: - case SHOPIFY_TRACK_MAP.orders_cancelled: - case SHOPIFY_TRACK_MAP.orders_fulfilled: - case SHOPIFY_TRACK_MAP.orders_paid: - case SHOPIFY_TRACK_MAP.orders_partially_fullfilled: - case RUDDER_ECOM_MAP.checkouts_create: - case RUDDER_ECOM_MAP.checkouts_update: - case RUDDER_ECOM_MAP.orders_create: - case RUDDER_ECOM_MAP.orders_updated: - message.setProperty( - 'anonymousId', - message.properties?.cart_token - ? sha256(message.properties.cart_token).toString().substring(0, 36) - : generateUUID(), - ); - break; - default: - message.setProperty('anonymousId', generateUUID()); - break; +const getAnonymousId = (message) => { + const cartToken = getCartToken(message); + if (isDefinedAndNotNull(cartToken)) { + return v5(cartToken, v5.URL); + } + if (SHOPIFY_ADMIN_ONLY_EVENTS.includes(message.event)) { + return null; } + return generateUUID(); + }; /** * This function sets the anonymousId based on cart_token or id from the properties of message. @@ -132,78 +110,98 @@ const setAnonymousId = (message) => { * @param {*} message * @returns */ -const setAnonymousIdorUserIdFromDb = async (message, metricMetadata) => { - let cartToken; - const { event, properties, userId } = message; - switch (event) { - /** - * Following events will contain cart_token and we will map it in cartToken - */ - case RUDDER_ECOM_MAP.checkouts_create: - case RUDDER_ECOM_MAP.checkouts_update: - case SHOPIFY_TRACK_MAP.checkouts_delete: - case SHOPIFY_TRACK_MAP.orders_cancelled: - case SHOPIFY_TRACK_MAP.orders_fulfilled: - case SHOPIFY_TRACK_MAP.orders_paid: - case SHOPIFY_TRACK_MAP.orders_partially_fullfilled: - case RUDDER_ECOM_MAP.orders_create: - case RUDDER_ECOM_MAP.orders_updated: - cartToken = properties?.cart_token; - break; - /* - * we dont have cart_token for carts_create and update events but have id and token field - * which later on for orders become cart_token so we are fethcing cartToken from id - */ - case SHOPIFY_TRACK_MAP.carts_create: - case SHOPIFY_TRACK_MAP.carts_update: - cartToken = properties?.id || properties?.token; - break; - // https://help.shopify.com/en/manual/orders/edit-orders -> order can be edited through shopify-admin only - // https://help.shopify.com/en/manual/orders/fulfillment/setting-up-fulfillment -> fullfillments wont include cartToken neither in manual or automatiic - default: - } +const getAnonymousIdFromDb = async (message, metricMetadata) => { + const cartToken = getCartToken(message); + const { event } = message; if (!isDefinedAndNotNull(cartToken)) { - stats.increment('shopify_no_cartToken', { + return null; + } + let anonymousId; + try { + anonymousId = await RedisDB.getVal(`${cartToken}`, 'anonymousId'); + } catch (e) { + stats.increment('shopify_redis_failures', { + type: 'get', ...metricMetadata, - event, - timestamp: Date.now(), }); - if (!userId) { - message.setProperty('userId', 'shopify-admin'); - } - return; } - let anonymousIDfromDB; - const executeStartTime = Date.now(); - const redisVal = await RedisDB.getVal(`${cartToken}`); - stats.timing('redis_get_latency', executeStartTime, { - ...metricMetadata, - }); - stats.increment('shopify_redis_get_data', { + stats.increment('shopify_redis_calls', { + type: 'get', ...metricMetadata, - timestamp: Date.now(), }); - if (redisVal !== null) { - anonymousIDfromDB = redisVal.anonymousId; - } - if (!isDefinedAndNotNull(anonymousIDfromDB)) { - /* this is for backward compatability when we don't have the redis mapping for older events - we will get anonymousIDFromDb as null so we will set UUID using the session Key */ - stats.increment('shopify_no_anon_id_from_redis', { + if (anonymousId === null) { + stats.increment('shopify_redis_no_val', { ...metricMetadata, event, - timestamp: Date.now(), - }); - anonymousIDfromDB = sha256(cartToken).toString().substring(0, 36); + }) + } + if (!isDefinedAndNotNull(anonymousId)) { + /* if redis does not have the mapping for cartToken as key (null) + or redis is down(undefined) + we will set anonymousId as sha256(cartToken) + */ + return v5(cartToken, v5.URL) } - message.setProperty('anonymousId', anonymousIDfromDB); + return anonymousId; }; +/** + * It checks if the event is valid or not based on previous cartItems + * @param {*} inputEvent + * @returns true if event is valid else false + */ +const isValidCartEvent = (newCartItems, prevCartItems) => !(prevCartItems === newCartItems); + +const updateCartItemsInRedis = async (cartToken, newCartItemsHash, metricMetadata) => { + const value = ["itemsHash", newCartItemsHash]; + try { + await RedisDB.setVal(`${cartToken}`, value); + } catch (e) { + stats.increment('shopify_redis_failures', { + type: "set", + ...metricMetadata, + }); + } + +} +const checkAndUpdateCartItems = async (inputEvent, metricMetadata) => { + const cartToken = inputEvent.token || inputEvent.id; + let itemsHash; + try { + itemsHash = await RedisDB.getVal(cartToken, 'itemsHash'); + if (!isDefinedAndNotNull(itemsHash)) { + stats.increment('shopify_redis_no_val', { + ...metricMetadata, + event: "carts_update", + }) + } + } catch (e) { + // so if redis is down we will send the event to downstream destinations + stats.increment('shopify_redis_failures', { + type: 'get', + ...metricMetadata, + }); + return true; + } + if (isDefinedAndNotNull(itemsHash)) { + const newCartItemsHash = getHashLineItems(inputEvent); + const isCartValid = isValidCartEvent(newCartItemsHash, itemsHash); + if (!isCartValid) { + return false; + } + await updateCartItemsInRedis(cartToken, newCartItemsHash, metricMetadata); + return true; + } + // if nothing is found for cartToken provided then we will return false as we dont want to pollute the downstream destinations + return false; +} module.exports = { getShopifyTopic, getProductsListFromLineItems, createPropertiesForEcomEvent, extractEmailFromPayload, - setAnonymousIdorUserIdFromDb, - setAnonymousId, + getAnonymousIdFromDb, + getAnonymousId, + checkAndUpdateCartItems, + getHashLineItems }; diff --git a/test/__mocks__/data/sources/redis/response.json b/test/__mocks__/data/sources/redis/response.json index 2ee1782d7b..2bd3eb2991 100644 --- a/test/__mocks__/data/sources/redis/response.json +++ b/test/__mocks__/data/sources/redis/response.json @@ -1,3 +1,6 @@ { - "redis_test_get": "redis_test_get_value" -} + "redis_test_get": "redis_test_get_value", + "redis_test_Object": { + "testVal": "testVal" + } +} \ No newline at end of file diff --git a/test/__mocks__/data/sources/shopify/response.json b/test/__mocks__/data/sources/shopify/response.json index c8b0e9c9c0..5bfa8c39ef 100644 --- a/test/__mocks__/data/sources/shopify/response.json +++ b/test/__mocks__/data/sources/shopify/response.json @@ -1,11 +1,22 @@ { "shopify_test1": { - "anonymousId": "anon_shopify_test1" + "anonymousId": "anon_shopify_test1", + "itemsHash": "\"EMPTY\"" + }, + "shopify_test3": { + "anonymousId": "anon_shopify_test1", + "itemsHash": "\"EMPTY\"" }, "shopify_test2": { - "anonymousId": "anon_shopify_test2" + "anonymousId": "anon_shopify_test2", + "itemsHash": "\"EMPTY\"" }, "shopify_test_cart": { - "anonymousId": "anon_shopify_test1" + "anonymousId": "anon_shopify_test1", + "itemsHash": "\"EMPTY\"" + }, + "shopify_test_duplicate_cart": { + "anonymousId": "anon_shopify_test1", + "itemsHash": "210e4c525d04ceaef92a0058f6794f8f32a1efd7debdacb502ca5cb59c0e55e2" } -} +} \ No newline at end of file diff --git a/test/__mocks__/redis.js b/test/__mocks__/redis.js index 3b1f07c205..b2f0132198 100644 --- a/test/__mocks__/redis.js +++ b/test/__mocks__/redis.js @@ -16,52 +16,94 @@ const getData = redisKey => { path.resolve(__dirname, `./data/sources/${directory}/response.json`) ); const data = JSON.parse(dataFile); - response = data[redisKey]; + const response = data[redisKey]; return response; } } - +let connectionRequestCount = 0; class Redis { constructor(data) { - this.status = "closed", - this.data = data - + this.host = data.host, + this.port = data.port, + this.password = data.password, + this.username = data.username, + this.enableReadyCheck = data.enableReadyCheck, + this.retryStrategy = data.retryStrategy; + this.status = "connecting"; }; get(key) { - if(key === "error"){ + if (key === "error") { throw new Error("Connection is Closed"); } const mockData = getData(key); if (mockData) { - return JSON.stringify(mockData); + return mockData; } else { return null; } } set(key, value) { - if(key === "error"){ + if (key === "error") { throw new Error("Connection is Closed"); } - this.data[key] = value; + return { + expire: (key) => { + return { + exec: () => { } + } + } + } } - setex(key,expiry, value) { - if(key === "error"){ - throw new Error("Connection is Closed"); + hget(key, internalKey) { + const obj = this.get(key); + if (obj === null) { + return null; + } + return obj[`${internalKey}`]; + } + multi() { + return { hmset: this.hmset, set: this.set } + }; + hmset(key, value) { + return { + expire: (key, expiryTime) => { + return { + exec: () => { } + } + } } - this.data[key] = value; + } + + changeEventToReadyStatus() { + setTimeout(() => { + this.status = "ready" + }, + 100); } connect() { - this.status = "ready" - return new Promise((resolve, reject) => { - resolve({ data: "OK", status: 200 }); - }); + if (connectionRequestCount > 0) { + this.status = "ready" + return new Promise((resolve, _) => { + resolve({ data: "OK", status: 200 }); + }); + } else { + connectionRequestCount += 1; + this.changeEventToReadyStatus(); + throw new Error("Connection is Closed"); + } + + } + on() { jest.fn() } + end(times) { + this.retryStrategy(times); + this.status = "end" } - on() { - return true; + disconnect() { + this.status = "closed"; } }; diff --git a/test/__tests__/data/redis/shopify_source.json b/test/__tests__/data/redis/shopify_source.json deleted file mode 100644 index 4f64bb9bf9..0000000000 --- a/test/__tests__/data/redis/shopify_source.json +++ /dev/null @@ -1,1111 +0,0 @@ -[ - { - "description": "Track Call -> carts_create with invalid cartToken", - "input": { - "id": "shopify_test3", - "query_parameters": { - "topic": ["carts_create"] - }, - "token": "shopify_test3", - "line_items": [], - "note": null, - "updated_at": "2023-02-10T12:16:07.251Z", - "created_at": "2023-02-10T12:05:04.402Z" - }, - "output": { - "anonymousId": "2cc03982fec47ef7ca76b4e028c375a51879", - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "carts_create" - }, - "event": "Cart Create", - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "properties": { - "created_at": "2023-02-10T12:05:04.402Z", - "id": "shopify_test3", - "note": null, - "products": [], - "token": "shopify_test3", - "updated_at": "2023-02-10T12:16:07.251Z" - } - } - }, - { - "description": "Track Call -> orders_delete with invalid cartToken", - "input": { - "id": "shopify_test3", - "query_parameters": { - "topic": ["orders_delete"] - }, - "line_items": [], - "note": null, - "updated_at": "2023-02-10T12:16:07.251Z", - "created_at": "2023-02-10T12:05:04.402Z" - }, - "output": { - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "orders_delete" - }, - "event": "Order Deleted", - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "userId": "shopify-admin", - "properties": { - "created_at": "2023-02-10T12:05:04.402Z", - "id": "shopify_test3", - "note": null, - "products": [], - "updated_at": "2023-02-10T12:16:07.251Z" - } - } - }, - { - "description": "Track Call -> checkouts_delete with invalid cartToken", - "input": { - "id": "shopify_test3", - "query_parameters": { - "topic": ["checkouts_delete"] - }, - "line_items": [], - "note": null, - "updated_at": "2023-02-10T12:16:07.251Z", - "created_at": "2023-02-10T12:05:04.402Z" - }, - "output": { - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "checkouts_delete" - }, - "event": "Checkout Deleted", - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "userId": "shopify-admin", - "properties": { - "created_at": "2023-02-10T12:05:04.402Z", - "id": "shopify_test3", - "note": null, - "products": [], - "updated_at": "2023-02-10T12:16:07.251Z" - } - } - }, - { - "description": "Track Call -> carts_update", - "input": { - "user_id": "rudder01", - "id": "shopify_test_cart", - "query_parameters": { - "topic": ["carts_update"] - }, - "token": "shopify_test_cart", - "email": "test@rudderstack.com", - "line_items": [ - { - "id": 44323300999443, - "properties": null, - "quantity": 1, - "variant_id": 44323300999443, - "key": "44323300999443:70b21df78d403673a8b5dbafd62f0559", - "discounted_price": "30.00", - "discounts": [], - "gift_card": false, - "grams": 0, - "line_price": "30.00", - "original_line_price": "30.00", - "original_price": "30.00", - "price": "30.00", - "product_id": 8100575674643, - "sku": "", - "taxable": true, - "title": "Shirt 2 - LARGE", - "total_discount": "0.00", - "vendor": "testAnant", - "discounted_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "original_line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.0", - "currency_code": "GBP" - } - } - } - ], - "note": null, - "updated_at": "2023-02-10T12:16:07.251Z", - "created_at": "2023-02-10T12:05:04.402Z" - }, - "output": { - "userId": "rudder01", - "anonymousId": "anon_shopify_test1", - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "carts_update" - }, - "event": "Cart Update", - "integrations": { - "SHOPIFY": true - }, - "traits": { - "email": "test@rudderstack.com" - }, - "type": "track", - "properties": { - "note": null, - "created_at": "2023-02-10T12:05:04.402Z", - "email": "test@rudderstack.com", - "id": "shopify_test_cart", - "products": [ - { - "id": 44323300999443, - "properties": null, - "quantity": 1, - "variant": "44323300999443 ", - "key": "44323300999443:70b21df78d403673a8b5dbafd62f0559", - "discounted_price": "30.00", - "discounts": [], - "gift_card": false, - "grams": 0, - "line_price": "30.00", - "original_line_price": "30.00", - "original_price": "30.00", - "price": "30.00", - "product_id": 8100575674643, - "taxable": true, - "title": "Shirt 2 - LARGE", - "total_discount": "0.00", - "brand": "testAnant", - "discounted_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "original_line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.0", - "currency_code": "GBP" - } - } - } - ], - "user_id": "rudder01", - "token": "shopify_test_cart", - "updated_at": "2023-02-10T12:16:07.251Z" - } - } - }, - { - "description": "Track Call -> orders_updated with empty line_items", - "input": { - "id": "shopify_test2", - "query_parameters": { - "topic": ["orders_updated"] - }, - "shipping_address": "abc", - "billing_address": "abc", - "customer": { - "first_name": "Test", - "last_name": "Person" - }, - "cart_token": null, - "checkout_id": 36601802719507, - "checkout_token": "checkout token", - "client_details": { - "accept_language": null, - "browser_height": null, - "browser_ip": "122.161.73.113", - "user_agent": "Mozilla/5.0 User Agent" - }, - "line_items": [], - "note": null, - "updated_at": "2023-02-10T12:16:07.251Z", - "created_at": "2023-02-10T12:05:04.402Z" - }, - "output": { - "userId": "shopify-admin", - "context": { - "cart_token": null, - "checkout_token": "checkout token", - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "orders_updated" - }, - "event": "Order Updated", - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "properties": { - "checkout_id": 36601802719507, - "checkout_token": "checkout token", - "client_details": { - "accept_language": null, - "browser_height": null, - "browser_ip": "122.161.73.113", - "user_agent": "Mozilla/5.0 User Agent" - }, - "order_id": "shopify_test2", - "created_at": "2023-02-10T12:05:04.402Z", - "products": [], - "updated_at": "2023-02-10T12:16:07.251Z" - }, - "traits": { - "shippingAddress": "abc", - "billingAddress": "abc", - "firstName": "Test", - "lastName": "Person" - }, - "timestamp": "2023-02-10T12:16:07.251Z" - } - }, - { - "description": "Track Call -> fullfillments_create", - "input": { - "query_parameters": { - "topic": ["fulfillments_create"] - }, - "order_id": "random", - "status": "success", - "created_at": "2023-02-10T07:44:06-05:00", - "service": "manual", - "updated_at": "2023-02-10T07:44:06-05:00", - "tracking_company": null, - "shipment_status": null, - "location_id": 77735330067, - "origin_address": null, - "destination": null, - "line_items": [ - { - "variant_id": "variantId", - "title": "bitter cloud", - "quantity": 1, - "sku": "", - "variant_title": null, - "vendor": "testAnant", - "fulfillment_service": "manual", - "product_id": 8100634689811, - "requires_shipping": true, - "taxable": true, - "gift_card": false, - "name": "bitter cloud", - "variant_inventory_management": null, - "properties": [], - "product_exists": true, - "fulfillable_quantity": 0, - "grams": 0, - "price": "9.54", - "total_discount": "0.00", - "fulfillment_status": "fulfilled", - "price_set": { - "shop_money": { - "amount": "9.54", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "9.54", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.00", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.00", - "currency_code": "GBP" - } - }, - "discount_allocations": [], - "duties": [], - "shopify-admin_graphql_api_id": "gid://shopify/LineItem/13729348059411", - "tax_lines": [] - } - ], - "tracking_number": null, - "tracking_numbers": [], - "tracking_url": null, - "tracking_urls": [], - "receipt": {}, - "name": "#1001.1", - "shopify-admin_graphql_api_id": "gid://shopify/Fulfillment/4655820210451" - }, - "output": { - "userId": "shopify-admin", - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "fulfillments_create" - }, - "event": "Fulfillments Create", - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "properties": { - "shopify-admin_graphql_api_id": "gid://shopify/Fulfillment/4655820210451", - "created_at": "2023-02-10T07:44:06-05:00", - "destination": null, - "location_id": 77735330067, - "name": "#1001.1", - "order_id": "random", - "origin_address": null, - "products": [ - { - "shopify-admin_graphql_api_id": "gid://shopify/LineItem/13729348059411", - "quantity": 1, - "product_exists": true, - "title": "bitter cloud", - "product_id": 8100634689811, - "properties": [], - "requires_shipping": true, - "tax_lines": [], - "variant": "variantId ", - "variant_inventory_management": null, - "price": "9.54", - "taxable": true, - "total_discount": "0.00", - "brand": "testAnant", - "fulfillable_quantity": 0, - "fulfillment_service": "manual", - "fulfillment_status": "fulfilled", - "gift_card": false, - "grams": 0, - "discount_allocations": [], - "duties": [], - "price_set": { - "shop_money": { - "amount": "9.54", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "9.54", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.00", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.00", - "currency_code": "GBP" - } - } - } - ], - "receipt": {}, - "service": "manual", - "shipment_status": null, - "status": "success", - "tracking_company": null, - "tracking_number": null, - "tracking_numbers": [], - "tracking_url": null, - "tracking_urls": [], - "updated_at": "2023-02-10T07:44:06-05:00" - } - } - }, - { - "description": "Track Call -> checkouts_update ", - "input": { - "id": "shopify_test2", - "query_parameters": { - "topic": ["checkouts_update"] - }, - "token": "shopify_test2", - "cart_token": "shopify_test2", - "line_items": [ - { - "id": 44323300999443, - "token": "shopify_test2", - "properties": null, - "quantity": 1, - "variant_id": 44323300999443, - "key": "44323300999443:ky", - "discounted_price": "30.00", - "discounts": [], - "gift_card": false, - "grams": 0, - "line_price": "30.00", - "original_line_price": "30.00", - "original_price": "30.00", - "price": "30.00", - "product_id": 8100575674643, - "sku": "", - "taxable": true, - "title": "Shirt 2 - LARGE", - "total_discount": "0.00", - "vendor": "testAnant", - "discounted_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "original_line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.0", - "currency_code": "GBP" - } - } - } - ], - "note": null, - "updated_at": "2023-02-10T12:16:07.251Z", - "created_at": "2023-02-10T12:05:04.402Z" - }, - "output": { - "anonymousId": "anon_shopify_test2", - "context": { - "cart_token": "shopify_test2", - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "checkouts_update" - }, - "event": "Checkout Updated", - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "properties": { - "created_at": "2023-02-10T12:05:04.402Z", - "cart_token": "shopify_test2", - "order_id": "shopify_test2", - "products": [ - { - "id": 44323300999443, - "properties": null, - "quantity": 1, - "variant": "44323300999443 ", - "key": "44323300999443:ky", - "discounted_price": "30.00", - "discounts": [], - "gift_card": false, - "grams": 0, - "line_price": "30.00", - "original_line_price": "30.00", - "original_price": "30.00", - "price": "30.00", - "product_id": 8100575674643, - "taxable": true, - "token": "shopify_test2", - "title": "Shirt 2 - LARGE", - "total_discount": "0.00", - "brand": "testAnant", - "discounted_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "original_line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.0", - "currency_code": "GBP" - } - } - } - ], - "token": "shopify_test2", - "updated_at": "2023-02-10T12:16:07.251Z" - }, - "timestamp": "2023-02-10T12:16:07.251Z" - } - }, - { - "description": "Track Call -> checkouts_update with null cartToken", - "input": { - "id": "shopify_test2", - "query_parameters": { - "topic": ["checkouts_update"] - }, - "cart_token": null, - "line_items": [ - { - "id": 44323300999443, - "properties": null, - "quantity": 1, - "variant_id": 44323300999443, - "key": "44323300999443:ky", - "discounted_price": "30.00", - "discounts": [], - "gift_card": false, - "grams": 0, - "line_price": "30.00", - "original_line_price": "30.00", - "original_price": "30.00", - "price": "30.00", - "product_id": 8100575674643, - "sku": "", - "taxable": true, - "title": "Shirt 2 - LARGE", - "total_discount": "0.00", - "vendor": "testAnant", - "discounted_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "original_line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.0", - "currency_code": "GBP" - } - } - } - ], - "note": null, - "updated_at": "2023-02-10T12:16:07.251Z", - "created_at": "2023-02-10T12:05:04.402Z" - }, - "output": { - "userId": "shopify-admin", - "context": { - "cart_token": null, - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "checkouts_update" - }, - "event": "Checkout Updated", - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "properties": { - "order_id": "shopify_test2", - "created_at": "2023-02-10T12:05:04.402Z", - "products": [ - { - "id": 44323300999443, - "properties": null, - "quantity": 1, - "variant": "44323300999443 ", - "key": "44323300999443:ky", - "discounted_price": "30.00", - "discounts": [], - "gift_card": false, - "grams": 0, - "line_price": "30.00", - "original_line_price": "30.00", - "original_price": "30.00", - "price": "30.00", - "product_id": 8100575674643, - "taxable": true, - "title": "Shirt 2 - LARGE", - "total_discount": "0.00", - "brand": "testAnant", - "discounted_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "original_line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.0", - "currency_code": "GBP" - } - } - } - ], - "updated_at": "2023-02-10T12:16:07.251Z" - }, - "timestamp": "2023-02-10T12:16:07.251Z" - } - }, - { - "description": "Track Call -> carts_update with invalid cartToken", - "input": { - "id": "shopify_test3", - "query_parameters": { - "topic": ["carts_update"] - }, - "token": "shopify_test3", - "line_items": [ - { - "id": 44323300999443, - "properties": null, - "quantity": 1, - "variant_id": 44323300999443, - "key": "44323300999443:70b21df78d403673a8b5dbafd62f0559", - "discounted_price": "30.00", - "discounts": [], - "gift_card": false, - "grams": 0, - "line_price": "30.00", - "original_line_price": "30.00", - "original_price": "30.00", - "price": "30.00", - "product_id": 8100575674643, - "sku": "", - "taxable": true, - "title": "Shirt 2 - LARGE", - "total_discount": "0.00", - "vendor": "testAnant", - "discounted_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "original_line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.0", - "currency_code": "GBP" - } - } - } - ], - "note": null, - "updated_at": "2023-02-10T12:16:07.251Z", - "created_at": "2023-02-10T12:05:04.402Z" - }, - "output": { - "anonymousId": "2cc03982fec47ef7ca76b4e028c375a51879", - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "carts_update" - }, - "event": "Cart Update", - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "properties": { - "created_at": "2023-02-10T12:05:04.402Z", - "id": "shopify_test3", - "note": null, - "products": [ - { - "id": 44323300999443, - "properties": null, - "quantity": 1, - "variant": "44323300999443 ", - "key": "44323300999443:70b21df78d403673a8b5dbafd62f0559", - "discounted_price": "30.00", - "discounts": [], - "gift_card": false, - "grams": 0, - "line_price": "30.00", - "original_line_price": "30.00", - "original_price": "30.00", - "price": "30.00", - "product_id": 8100575674643, - "taxable": true, - "title": "Shirt 2 - LARGE", - "total_discount": "0.00", - "brand": "testAnant", - "discounted_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "original_line_price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "price_set": { - "shop_money": { - "amount": "30.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "30.0", - "currency_code": "GBP" - } - }, - "total_discount_set": { - "shop_money": { - "amount": "0.0", - "currency_code": "GBP" - }, - "presentment_money": { - "amount": "0.0", - "currency_code": "GBP" - } - } - } - ], - "token": "shopify_test3", - "updated_at": "2023-02-10T12:16:07.251Z" - } - } - }, - { - "description": "Rudder Identifier Event", - "input": { - "event": "rudderIdentifier", - "anonymousId": "b9993cc5-9e60-4e69-be0e-4e38c228314b", - "cartToken": "shopify_test1", - "query_parameters": { - "writeKey": ["Shopify Write Key"] - }, - "cart": { - "token": "token", - "id": "id", - "updated_at": "2023-02-10T07:44:06-05:00", - "line_items": [] - } - }, - "output": { - "outputToSource": { - "body": "T0s=", - "contentType": "text/plain" - }, - "statusCode": 200 - } - } -] diff --git a/test/__tests__/data/shopify.json b/test/__tests__/data/shopify.json index e37512236c..813c8cdc06 100644 --- a/test/__tests__/data/shopify.json +++ b/test/__tests__/data/shopify.json @@ -1,809 +1,843 @@ [ - { - "description": "Track Call -> carts_create with invalid cartToken", - "input": { - "id": "shopify_test3", - "query_parameters": { - "topic": ["carts_create"] - }, - "token": "shopify_test3", - "line_items": [], - "note": null, - "updated_at": "2023-02-10T12:16:07.251Z", - "created_at": "2023-02-10T12:05:04.402Z" - }, - "output": { - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" + { + "description": "Track Call -> carts_create with invalid cartToken", + "input": { + "id": "shopify_test3", + "query_parameters": { + "topic": [ + "carts_create" + ] + }, + "token": "shopify_test3", + "line_items": [], + "note": null, + "updated_at": "2023-02-10T12:16:07.251Z", + "created_at": "2023-02-10T12:05:04.402Z" }, - "topic": "carts_create" - }, - "event": "Cart Create", - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "properties": { - "created_at": "2023-02-10T12:05:04.402Z", - "id": "shopify_test3", - "note": null, - "products": [], - "token": "shopify_test3", - "updated_at": "2023-02-10T12:16:07.251Z" - } - } - }, - { - "description": "No Query Parameters", - "input": {}, - "output": { - "error": "Query_parameters is missing" - } - }, - { - "description": "Invalid topic", - "input": { - "query_parameters": { - "signature": ["rudderstack"], - "writeKey": ["sample-write-key"] - } - }, - "output": { - "error": "Invalid topic in query_parameters" - } - }, - { - "description": "Topic Not found", - "input": { - "query_parameters": { - "topic": [], - "signature": ["rudderstack"], - "writeKey": ["sample-write-key"] - } + "output": { + "error": "event type carts_create not supported" + } }, - "output": { - "error": "Topic not found" - } - }, - { - "description": "Unsupported Event Type", - "input": { - "query_parameters": { - "topic": ["random_event"], - "signature": ["rudderstack"], - "writeKey": ["sample-write-key"] - } + { + "description": "No Query Parameters", + "input": {}, + "output": { + "error": "Query_parameters is missing" + } }, - "output": { - "error": "event type random_event not supported" - } - }, - { - "description": "Identify Call for customers create event", - "input": { - "query_parameters": { - "topic": ["customers_create"], - "signature": ["rudderstack"], - "writeKey": ["sample-write-key"] - }, - "id": 5747017285820, - "email": "anuraj@rudderstack.com", - "accepts_marketing": false, - "created_at": "2021-12-29T15:15:19+05:30", - "updated_at": "2021-12-29T15:15:20+05:30", - "first_name": "Anuraj", - "last_name": "Guha", - "orders_count": 0, - "state": "disabled", - "total_spent": "0.00", - "last_order_id": null, - "note": "", - "verified_email": true, - "multipass_identifier": null, - "tax_exempt": false, - "phone": "+919876543210", - "tags": "", - "last_order_name": null, - "currency": "INR", - "addresses": [ - { - "id": 6947581821116, - "customer_id": 5747017285820, - "first_name": "Anuraj", - "last_name": "Guha", - "company": "Rudderstack", - "address1": "Home", - "address2": "Apartment", - "city": "Kolkata", - "province": "West Bengal", - "country": "India", - "zip": "708091", - "phone": "+919876543210", - "name": "Anuraj Guha", - "province_code": "WB", - "country_code": "IN", - "country_name": "India", - "default": true + { + "description": "Invalid topic", + "input": { + "query_parameters": { + "signature": [ + "rudderstack" + ], + "writeKey": [ + "sample-write-key" + ] + } + }, + "output": { + "error": "Invalid topic in query_parameters" } - ], - "accepts_marketing_updated_at": "2021-12-29T15:15:20+05:30", - "marketing_opt_in_level": null, - "tax_exemptions": [], - "sms_marketing_consent": { - "state": "not_subscribed", - "opt_in_level": "single_opt_in", - "consent_updated_at": null, - "consent_collected_from": "SHOPIFY" - }, - "admin_graphql_api_id": "gid://shopify/Customer/5747017285820", - "default_address": { - "id": 6947581821116, - "customer_id": 5747017285820, - "first_name": "Anuraj", - "last_name": "Guha", - "company": "Rudderstack", - "address1": "Home", - "address2": "Apartment", - "city": "Kolkata", - "province": "West Bengal", - "country": "India", - "zip": "708091", - "phone": "+919876543210", - "name": "Anuraj Guha", - "province_code": "WB", - "country_code": "IN", - "country_name": "India", - "default": true - } }, - "output": { - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" + { + "description": "Topic Not found", + "input": { + "query_parameters": { + "topic": [], + "signature": [ + "rudderstack" + ], + "writeKey": [ + "sample-write-key" + ] + } }, - "integration": { - "name": "SHOPIFY" + "output": { + "error": "Topic not found" + } + }, + { + "description": "Unsupported Event Type", + "input": { + "query_parameters": { + "topic": [ + "random_event" + ], + "signature": [ + "rudderstack" + ], + "writeKey": [ + "sample-write-key" + ] + } }, - "topic": "customers_create" - }, - "integrations": { - "SHOPIFY": true - }, - "type": "identify", - "userId": "5747017285820", - "traits": { - "email": "anuraj@rudderstack.com", - "firstName": "Anuraj", - "lastName": "Guha", - "phone": "+919876543210", - "addressList": [ - { - "id": 6947581821116, - "customer_id": 5747017285820, + "output": { + "error": "event type random_event not supported" + } + }, + { + "description": "Identify Call for customers create event", + "input": { + "query_parameters": { + "topic": [ + "customers_create" + ], + "signature": [ + "rudderstack" + ], + "writeKey": [ + "sample-write-key" + ] + }, + "id": 5747017285820, + "email": "anuraj@rudderstack.com", + "accepts_marketing": false, + "created_at": "2021-12-29T15:15:19+05:30", + "updated_at": "2021-12-29T15:15:20+05:30", "first_name": "Anuraj", "last_name": "Guha", - "company": "Rudderstack", - "address1": "Home", - "address2": "Apartment", - "city": "Kolkata", - "province": "West Bengal", - "country": "India", - "zip": "708091", + "orders_count": 0, + "state": "disabled", + "total_spent": "0.00", + "last_order_id": null, + "note": "", + "verified_email": true, + "multipass_identifier": null, + "tax_exempt": false, "phone": "+919876543210", - "name": "Anuraj Guha", - "province_code": "WB", - "country_code": "IN", - "country_name": "India", - "default": true - } - ], - "address": { - "id": 6947581821116, - "customer_id": 5747017285820, - "first_name": "Anuraj", - "last_name": "Guha", - "company": "Rudderstack", - "address1": "Home", - "address2": "Apartment", - "city": "Kolkata", - "province": "West Bengal", - "country": "India", - "zip": "708091", - "phone": "+919876543210", - "name": "Anuraj Guha", - "province_code": "WB", - "country_code": "IN", - "country_name": "India", - "default": true - }, - "acceptsMarketing": false, - "orderCount": 0, - "state": "disabled", - "totalSpent": "0.00", - "note": "", - "verifiedEmail": true, - "taxExempt": false, - "tags": "", - "currency": "INR", - "taxExemptions": [], - "smsMarketingConsent": { - "state": "not_subscribed", - "opt_in_level": "single_opt_in", - "consent_updated_at": null, - "consent_collected_from": "SHOPIFY" - }, - "adminGraphqlApiId": "gid://shopify/Customer/5747017285820", - "acceptsMarketingUpdatedAt": "2021-12-29T15:15:20+05:30" - }, - "timestamp": "2021-12-29T09:45:20.000Z" - } - }, - { - "description": "Unsupported checkout event", - "input": { - "query_parameters": { - "topic": ["checkout_delete"], - "writeKey": ["sample-write-key"], - "signature": ["rudderstack"] - }, - "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", - "created_at": "2022-01-05T18:13:02+05:30", - "destination": null, - "id": 4124667937024, - "line_items": [], - "customer": { - "email": "test_person@email.com", - "first_name": "Test", - "last_name": "Person" - }, - "billing_address": { - "address1": "11 Rani Sankari Lane Patuapara Bhowanipore" - }, - "shipping_address": { - "address1": "11 Rani Sankari Lane Patuapara Bhowanipore" - }, - "location_id": 66855371008, - "name": "#1002.1", - "order_id": 4617255092480, - "origin_address": null, - "receipt": {}, - "service": "manual", - "shipment_status": null, - "status": "success", - "tracking_company": "Amazon Logistics UK", - "tracking_number": "Sample001test", - "tracking_numbers": ["Sample001test"], - "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", - "tracking_urls": ["https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530"], - "updated_at": "2022-01-05T18:16:48+05:30" - }, - "output": { - "error": "event type checkout_delete not supported" - } - }, - { - "description": "Track Call -> Fullfillments updated event", - "input": { - "query_parameters": { - "topic": ["fulfillments_update"], - "writeKey": ["sample-write-key"], - "signature": ["rudderstack"] - }, - "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", - "created_at": "2022-01-05T18:13:02+05:30", - "destination": null, - "email": "test_person@email.com", - "id": 4124667937024, - "line_items": [ - { - "admin_graphql_api_id": "gid://shopify/LineItem/11896203149568", - "discount_allocations": [], - "duties": [], - "fulfillable_quantity": 0, - "fulfillment_service": "manual", - "fulfillment_status": "fulfilled", - "gift_card": false, - "grams": 0, - "id": 11896203149568, - "name": "p1", - "origin_location": { - "address1": "74 CC/7, Anupama Housing Estate - II", - "address2": "", - "city": "Kolkatta", - "country_code": "IN", - "id": 3373642219776, - "name": "74 CC/7, Anupama Housing Estate - II", - "province_code": "WB", - "zip": "700052" - }, - "price": "5000.00", - "price_set": { - "presentment_money": { - "amount": "5000.00", - "currency_code": "INR" + "tags": "", + "last_order_name": null, + "currency": "INR", + "addresses": [ + { + "id": 6947581821116, + "customer_id": 5747017285820, + "first_name": "Anuraj", + "last_name": "Guha", + "company": "Rudderstack", + "address1": "Home", + "address2": "Apartment", + "city": "Kolkata", + "province": "West Bengal", + "country": "India", + "zip": "708091", + "phone": "+919876543210", + "name": "Anuraj Guha", + "province_code": "WB", + "country_code": "IN", + "country_name": "India", + "default": true + } + ], + "accepts_marketing_updated_at": "2021-12-29T15:15:20+05:30", + "marketing_opt_in_level": null, + "tax_exemptions": [], + "sms_marketing_consent": { + "state": "not_subscribed", + "opt_in_level": "single_opt_in", + "consent_updated_at": null, + "consent_collected_from": "SHOPIFY" }, - "shop_money": { - "amount": "5000.00", - "currency_code": "INR" + "admin_graphql_api_id": "gid://shopify/Customer/5747017285820", + "default_address": { + "id": 6947581821116, + "customer_id": 5747017285820, + "first_name": "Anuraj", + "last_name": "Guha", + "company": "Rudderstack", + "address1": "Home", + "address2": "Apartment", + "city": "Kolkata", + "province": "West Bengal", + "country": "India", + "zip": "708091", + "phone": "+919876543210", + "name": "Anuraj Guha", + "province_code": "WB", + "country_code": "IN", + "country_name": "India", + "default": true } - }, - "product_exists": true, - "product_id": 7510929801472, - "properties": [], - "quantity": 1, - "requires_shipping": true, - "sku": "15", - "tax_lines": [ - { - "channel_liable": false, - "price": "900.00", - "price_set": { - "presentment_money": { - "amount": "900.00", - "currency_code": "INR" + }, + "output": { + "context": { + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" }, - "shop_money": { - "amount": "900.00", - "currency_code": "INR" - } - }, - "rate": 0.18, - "title": "IGST" - } - ], - "taxable": true, - "title": "p1", - "total_discount": "0.00", - "total_discount_set": { - "presentment_money": { - "amount": "0.00", - "currency_code": "INR" + "integration": { + "name": "SHOPIFY" + }, + "topic": "customers_create" }, - "shop_money": { - "amount": "0.00", - "currency_code": "INR" - } - }, - "variant_id": 42211160228096, - "variant_inventory_management": "shopify", - "variant_title": "", - "vendor": "rudderstack-store" + "integrations": { + "SHOPIFY": true + }, + "type": "identify", + "userId": "5747017285820", + "traits": { + "email": "anuraj@rudderstack.com", + "firstName": "Anuraj", + "lastName": "Guha", + "phone": "+919876543210", + "addressList": [ + { + "id": 6947581821116, + "customer_id": 5747017285820, + "first_name": "Anuraj", + "last_name": "Guha", + "company": "Rudderstack", + "address1": "Home", + "address2": "Apartment", + "city": "Kolkata", + "province": "West Bengal", + "country": "India", + "zip": "708091", + "phone": "+919876543210", + "name": "Anuraj Guha", + "province_code": "WB", + "country_code": "IN", + "country_name": "India", + "default": true + } + ], + "address": { + "id": 6947581821116, + "customer_id": 5747017285820, + "first_name": "Anuraj", + "last_name": "Guha", + "company": "Rudderstack", + "address1": "Home", + "address2": "Apartment", + "city": "Kolkata", + "province": "West Bengal", + "country": "India", + "zip": "708091", + "phone": "+919876543210", + "name": "Anuraj Guha", + "province_code": "WB", + "country_code": "IN", + "country_name": "India", + "default": true + }, + "acceptsMarketing": false, + "orderCount": 0, + "state": "disabled", + "totalSpent": "0.00", + "note": "", + "verifiedEmail": true, + "taxExempt": false, + "tags": "", + "currency": "INR", + "taxExemptions": [], + "smsMarketingConsent": { + "state": "not_subscribed", + "opt_in_level": "single_opt_in", + "consent_updated_at": null, + "consent_collected_from": "SHOPIFY" + }, + "adminGraphqlApiId": "gid://shopify/Customer/5747017285820", + "acceptsMarketingUpdatedAt": "2021-12-29T15:15:20+05:30" + }, + "timestamp": "2021-12-29T09:45:20.000Z" } - ], - "location_id": 66855371008, - "name": "#1002.1", - "order_id": 4617255092480, - "origin_address": null, - "receipt": {}, - "service": "manual", - "shipment_status": null, - "status": "success", - "tracking_company": "Amazon Logistics UK", - "tracking_number": "Sample001test", - "tracking_numbers": ["Sample001test"], - "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", - "tracking_urls": ["https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530"], - "updated_at": "2022-01-05T18:16:48+05:30" }, - "output": { - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "fulfillments_update" - }, - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "userId": "shopify-admin", - "event": "Fulfillments Update", - "properties": { - "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", - "created_at": "2022-01-05T18:13:02+05:30", - "destination": null, - "email": "test_person@email.com", - "id": 4124667937024, - "location_id": 66855371008, - "name": "#1002.1", - "order_id": 4617255092480, - "origin_address": null, - "receipt": {}, - "service": "manual", - "shipment_status": null, - "status": "success", - "tracking_company": "Amazon Logistics UK", - "tracking_number": "Sample001test", - "tracking_numbers": ["Sample001test"], - "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", - "tracking_urls": [ - "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530" - ], - "updated_at": "2022-01-05T18:16:48+05:30", - "products": [ - { - "product_id": 7510929801472, - "sku": "15", - "title": "p1", - "price": "5000.00", - "brand": "rudderstack-store", - "quantity": 1, - "admin_graphql_api_id": "gid://shopify/LineItem/11896203149568", - "discount_allocations": [], - "duties": [], - "fulfillable_quantity": 0, - "fulfillment_service": "manual", - "fulfillment_status": "fulfilled", - "gift_card": false, - "grams": 0, - "id": 11896203149568, - "origin_location": { - "address1": "74 CC/7, Anupama Housing Estate - II", - "address2": "", - "city": "Kolkatta", - "country_code": "IN", - "id": 3373642219776, - "name": "74 CC/7, Anupama Housing Estate - II", - "province_code": "WB", - "zip": "700052" + { + "description": "Unsupported checkout event", + "input": { + "query_parameters": { + "topic": [ + "checkout_delete" + ], + "writeKey": [ + "sample-write-key" + ], + "signature": [ + "rudderstack" + ] }, - "price_set": { - "presentment_money": { - "amount": "5000.00", - "currency_code": "INR" - }, - "shop_money": { - "amount": "5000.00", - "currency_code": "INR" - } + "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", + "created_at": "2022-01-05T18:13:02+05:30", + "destination": null, + "id": 4124667937024, + "line_items": [], + "customer": { + "email": "test_person@email.com", + "first_name": "Test", + "last_name": "Person" }, - "product_exists": true, - "properties": [], - "requires_shipping": true, - "tax_lines": [ - { - "channel_liable": false, - "price": "900.00", - "price_set": { - "presentment_money": { - "amount": "900.00", - "currency_code": "INR" - }, - "shop_money": { - "amount": "900.00", - "currency_code": "INR" - } - }, - "rate": 0.18, - "title": "IGST" - } - ], - "taxable": true, - "total_discount": "0.00", - "total_discount_set": { - "presentment_money": { - "amount": "0.00", - "currency_code": "INR" - }, - "shop_money": { - "amount": "0.00", - "currency_code": "INR" - } + "billing_address": { + "address1": "11 Rani Sankari Lane Patuapara Bhowanipore" }, - "variant_inventory_management": "shopify", - "variant": "42211160228096 " - } - ] - }, - "traits": { - "email": "test_person@email.com" - } - } - }, - { - "description": "Track Call -> Fullfillments updated event with traits", - "input": { - "query_parameters": { - "topic": ["fulfillments_update"], - "writeKey": ["sample-write-key"], - "signature": ["rudderstack"] - }, - "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", - "created_at": "2022-01-05T18:13:02+05:30", - "destination": null, - "id": 4124667937024, - "line_items": [ - { - "admin_graphql_api_id": "gid://shopify/LineItem/11896203149568", - "discount_allocations": [], - "duties": [], - "fulfillable_quantity": 0, - "fulfillment_service": "manual", - "fulfillment_status": "fulfilled", - "gift_card": false, - "grams": 0, - "id": 11896203149568, - "name": "p1", - "origin_location": { - "address1": "74 CC/7, Anupama Housing Estate - II", - "address2": "", - "city": "Kolkatta", - "country_code": "IN", - "id": 3373642219776, - "name": "74 CC/7, Anupama Housing Estate - II", - "province_code": "WB", - "zip": "700052" - }, - "price": "5000.00", - "price_set": { - "presentment_money": { - "amount": "5000.00", - "currency_code": "INR" + "shipping_address": { + "address1": "11 Rani Sankari Lane Patuapara Bhowanipore" }, - "shop_money": { - "amount": "5000.00", - "currency_code": "INR" - } - }, - "product_exists": true, - "product_id": 7510929801472, - "properties": [], - "quantity": 1, - "requires_shipping": true, - "sku": "15", - "tax_lines": [ - { - "channel_liable": false, - "price": "900.00", - "price_set": { - "presentment_money": { - "amount": "900.00", - "currency_code": "INR" - }, - "shop_money": { - "amount": "900.00", - "currency_code": "INR" + "location_id": 66855371008, + "name": "#1002.1", + "order_id": 4617255092480, + "origin_address": null, + "receipt": {}, + "service": "manual", + "shipment_status": null, + "status": "success", + "tracking_company": "Amazon Logistics UK", + "tracking_number": "Sample001test", + "tracking_numbers": [ + "Sample001test" + ], + "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", + "tracking_urls": [ + "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530" + ], + "updated_at": "2022-01-05T18:16:48+05:30" + }, + "output": { + "error": "event type checkout_delete not supported" + } + }, + { + "description": "Track Call -> Fullfillments updated event", + "input": { + "query_parameters": { + "topic": [ + "fulfillments_update" + ], + "writeKey": [ + "sample-write-key" + ], + "signature": [ + "rudderstack" + ] + }, + "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", + "created_at": "2022-01-05T18:13:02+05:30", + "destination": null, + "email": "test_person@email.com", + "id": 4124667937024, + "line_items": [ + { + "admin_graphql_api_id": "gid://shopify/LineItem/11896203149568", + "discount_allocations": [], + "duties": [], + "fulfillable_quantity": 0, + "fulfillment_service": "manual", + "fulfillment_status": "fulfilled", + "gift_card": false, + "grams": 0, + "id": 11896203149568, + "name": "p1", + "origin_location": { + "address1": "74 CC/7, Anupama Housing Estate - II", + "address2": "", + "city": "Kolkatta", + "country_code": "IN", + "id": 3373642219776, + "name": "74 CC/7, Anupama Housing Estate - II", + "province_code": "WB", + "zip": "700052" + }, + "price": "5000.00", + "price_set": { + "presentment_money": { + "amount": "5000.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "5000.00", + "currency_code": "INR" + } + }, + "product_exists": true, + "product_id": 7510929801472, + "properties": [], + "quantity": 1, + "requires_shipping": true, + "sku": "15", + "tax_lines": [ + { + "channel_liable": false, + "price": "900.00", + "price_set": { + "presentment_money": { + "amount": "900.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "900.00", + "currency_code": "INR" + } + }, + "rate": 0.18, + "title": "IGST" + } + ], + "taxable": true, + "title": "p1", + "total_discount": "0.00", + "total_discount_set": { + "presentment_money": { + "amount": "0.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "0.00", + "currency_code": "INR" + } + }, + "variant_id": 42211160228096, + "variant_inventory_management": "shopify", + "variant_title": "", + "vendor": "rudderstack-store" } - }, - "rate": 0.18, - "title": "IGST" - } - ], - "taxable": true, - "title": "p1", - "total_discount": "0.00", - "total_discount_set": { - "presentment_money": { - "amount": "0.00", - "currency_code": "INR" + ], + "location_id": 66855371008, + "name": "#1002.1", + "order_id": 4617255092480, + "origin_address": null, + "receipt": {}, + "service": "manual", + "shipment_status": null, + "status": "success", + "tracking_company": "Amazon Logistics UK", + "tracking_number": "Sample001test", + "tracking_numbers": [ + "Sample001test" + ], + "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", + "tracking_urls": [ + "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530" + ], + "updated_at": "2022-01-05T18:16:48+05:30" + }, + "output": { + "context": { + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" + }, + "integration": { + "name": "SHOPIFY" + }, + "topic": "fulfillments_update" + }, + "integrations": { + "SHOPIFY": true }, - "shop_money": { - "amount": "0.00", - "currency_code": "INR" + "type": "track", + "userId": "shopify-admin", + "event": "Fulfillments Update", + "properties": { + "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", + "created_at": "2022-01-05T18:13:02+05:30", + "destination": null, + "email": "test_person@email.com", + "id": 4124667937024, + "location_id": 66855371008, + "name": "#1002.1", + "order_id": 4617255092480, + "origin_address": null, + "receipt": {}, + "service": "manual", + "shipment_status": null, + "status": "success", + "tracking_company": "Amazon Logistics UK", + "tracking_number": "Sample001test", + "tracking_numbers": [ + "Sample001test" + ], + "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", + "tracking_urls": [ + "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530" + ], + "updated_at": "2022-01-05T18:16:48+05:30", + "products": [ + { + "product_id": 7510929801472, + "sku": "15", + "title": "p1", + "price": "5000.00", + "brand": "rudderstack-store", + "quantity": 1, + "admin_graphql_api_id": "gid://shopify/LineItem/11896203149568", + "discount_allocations": [], + "duties": [], + "fulfillable_quantity": 0, + "fulfillment_service": "manual", + "fulfillment_status": "fulfilled", + "gift_card": false, + "grams": 0, + "id": 11896203149568, + "origin_location": { + "address1": "74 CC/7, Anupama Housing Estate - II", + "address2": "", + "city": "Kolkatta", + "country_code": "IN", + "id": 3373642219776, + "name": "74 CC/7, Anupama Housing Estate - II", + "province_code": "WB", + "zip": "700052" + }, + "price_set": { + "presentment_money": { + "amount": "5000.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "5000.00", + "currency_code": "INR" + } + }, + "product_exists": true, + "properties": [], + "requires_shipping": true, + "tax_lines": [ + { + "channel_liable": false, + "price": "900.00", + "price_set": { + "presentment_money": { + "amount": "900.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "900.00", + "currency_code": "INR" + } + }, + "rate": 0.18, + "title": "IGST" + } + ], + "taxable": true, + "total_discount": "0.00", + "total_discount_set": { + "presentment_money": { + "amount": "0.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "0.00", + "currency_code": "INR" + } + }, + "variant_inventory_management": "shopify", + "variant": "42211160228096 " + } + ] + }, + "traits": { + "email": "test_person@email.com" } - }, - "variant_id": 42211160228096, - "variant_inventory_management": "shopify", - "variant_title": "", - "vendor": "rudderstack-store" } - ], - "customer": { - "email": "test_person@email.com", - "first_name": "Test", - "last_name": "Person" - }, - "billing_address": { - "address1": "11 Rani Sankari Lane Patuapara Bhowanipore", - "address2": "", - "city": "Kolkata", - "company": null, - "country": "India", - "country_code": "IN", - "first_name": "Utsab", - "last_name": "Chowdhury", - "latitude": null, - "longitude": null, - "name": "Utsab Chowdhury", - "phone": null, - "province": "West Bengal", - "province_code": "WB", - "zip": "700025" - }, - "shipping_address": { - "address1": "11 Rani Sankari Lane Patuapara Bhowanipore", - "address2": "", - "city": "Kolkata", - "company": null, - "country": "India", - "country_code": "IN", - "first_name": "Utsab", - "last_name": "Chowdhury", - "latitude": null, - "longitude": null, - "name": "Utsab Chowdhury", - "phone": null, - "province": "West Bengal", - "province_code": "WB", - "zip": "700025" - }, - "location_id": 66855371008, - "name": "#1002.1", - "order_id": 4617255092480, - "origin_address": null, - "receipt": {}, - "service": "manual", - "shipment_status": null, - "status": "success", - "tracking_company": "Amazon Logistics UK", - "tracking_number": "Sample001test", - "tracking_numbers": ["Sample001test"], - "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", - "tracking_urls": ["https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530"], - "updated_at": "2022-01-05T18:16:48+05:30" }, - "output": { - "context": { - "library": { - "name": "RudderStack Shopify Cloud", - "version": "1.0.0" - }, - "integration": { - "name": "SHOPIFY" - }, - "topic": "fulfillments_update" - }, - "integrations": { - "SHOPIFY": true - }, - "type": "track", - "event": "Fulfillments Update", - "userId": "shopify-admin", - "properties": { - "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", - "created_at": "2022-01-05T18:13:02+05:30", - "destination": null, - "id": 4124667937024, - "location_id": 66855371008, - "name": "#1002.1", - "order_id": 4617255092480, - "origin_address": null, - "receipt": {}, - "service": "manual", - "shipment_status": null, - "status": "success", - "tracking_company": "Amazon Logistics UK", - "tracking_number": "Sample001test", - "tracking_numbers": ["Sample001test"], - "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", - "tracking_urls": [ - "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530" - ], - "updated_at": "2022-01-05T18:16:48+05:30", - "products": [ - { - "product_id": 7510929801472, - "sku": "15", - "title": "p1", - "price": "5000.00", - "brand": "rudderstack-store", - "quantity": 1, - "admin_graphql_api_id": "gid://shopify/LineItem/11896203149568", - "discount_allocations": [], - "duties": [], - "fulfillable_quantity": 0, - "fulfillment_service": "manual", - "fulfillment_status": "fulfilled", - "gift_card": false, - "grams": 0, - "id": 11896203149568, - "origin_location": { - "address1": "74 CC/7, Anupama Housing Estate - II", - "address2": "", - "city": "Kolkatta", - "country_code": "IN", - "id": 3373642219776, - "name": "74 CC/7, Anupama Housing Estate - II", - "province_code": "WB", - "zip": "700052" + { + "description": "Track Call -> Fullfillments updated event with traits", + "input": { + "query_parameters": { + "topic": [ + "fulfillments_update" + ], + "writeKey": [ + "sample-write-key" + ], + "signature": [ + "rudderstack" + ] }, - "price_set": { - "presentment_money": { - "amount": "5000.00", - "currency_code": "INR" - }, - "shop_money": { - "amount": "5000.00", - "currency_code": "INR" - } - }, - "product_exists": true, - "properties": [], - "requires_shipping": true, - "tax_lines": [ - { - "channel_liable": false, - "price": "900.00", - "price_set": { - "presentment_money": { - "amount": "900.00", - "currency_code": "INR" - }, - "shop_money": { - "amount": "900.00", - "currency_code": "INR" - } - }, - "rate": 0.18, - "title": "IGST" - } + "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", + "created_at": "2022-01-05T18:13:02+05:30", + "destination": null, + "id": 4124667937024, + "line_items": [ + { + "admin_graphql_api_id": "gid://shopify/LineItem/11896203149568", + "discount_allocations": [], + "duties": [], + "fulfillable_quantity": 0, + "fulfillment_service": "manual", + "fulfillment_status": "fulfilled", + "gift_card": false, + "grams": 0, + "id": 11896203149568, + "name": "p1", + "origin_location": { + "address1": "74 CC/7, Anupama Housing Estate - II", + "address2": "", + "city": "Kolkatta", + "country_code": "IN", + "id": 3373642219776, + "name": "74 CC/7, Anupama Housing Estate - II", + "province_code": "WB", + "zip": "700052" + }, + "price": "5000.00", + "price_set": { + "presentment_money": { + "amount": "5000.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "5000.00", + "currency_code": "INR" + } + }, + "product_exists": true, + "product_id": 7510929801472, + "properties": [], + "quantity": 1, + "requires_shipping": true, + "sku": "15", + "tax_lines": [ + { + "channel_liable": false, + "price": "900.00", + "price_set": { + "presentment_money": { + "amount": "900.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "900.00", + "currency_code": "INR" + } + }, + "rate": 0.18, + "title": "IGST" + } + ], + "taxable": true, + "title": "p1", + "total_discount": "0.00", + "total_discount_set": { + "presentment_money": { + "amount": "0.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "0.00", + "currency_code": "INR" + } + }, + "variant_id": 42211160228096, + "variant_inventory_management": "shopify", + "variant_title": "", + "vendor": "rudderstack-store" + } ], - "taxable": true, - "total_discount": "0.00", - "total_discount_set": { - "presentment_money": { - "amount": "0.00", - "currency_code": "INR" - }, - "shop_money": { - "amount": "0.00", - "currency_code": "INR" - } + "customer": { + "email": "test_person@email.com", + "first_name": "Test", + "last_name": "Person" + }, + "billing_address": { + "address1": "11 Rani Sankari Lane Patuapara Bhowanipore", + "address2": "", + "city": "Kolkata", + "company": null, + "country": "India", + "country_code": "IN", + "first_name": "Utsab", + "last_name": "Chowdhury", + "latitude": null, + "longitude": null, + "name": "Utsab Chowdhury", + "phone": null, + "province": "West Bengal", + "province_code": "WB", + "zip": "700025" }, - "variant_inventory_management": "shopify", - "variant": "42211160228096 " - } - ] - }, - "traits": { - "email": "test_person@email.com", - "firstName": "Test", - "lastName": "Person", - "shippingAddress": { - "address1": "11 Rani Sankari Lane Patuapara Bhowanipore", - "address2": "", - "city": "Kolkata", - "company": null, - "country": "India", - "country_code": "IN", - "first_name": "Utsab", - "last_name": "Chowdhury", - "latitude": null, - "longitude": null, - "name": "Utsab Chowdhury", - "phone": null, - "province": "West Bengal", - "province_code": "WB", - "zip": "700025" + "shipping_address": { + "address1": "11 Rani Sankari Lane Patuapara Bhowanipore", + "address2": "", + "city": "Kolkata", + "company": null, + "country": "India", + "country_code": "IN", + "first_name": "Utsab", + "last_name": "Chowdhury", + "latitude": null, + "longitude": null, + "name": "Utsab Chowdhury", + "phone": null, + "province": "West Bengal", + "province_code": "WB", + "zip": "700025" + }, + "location_id": 66855371008, + "name": "#1002.1", + "order_id": 4617255092480, + "origin_address": null, + "receipt": {}, + "service": "manual", + "shipment_status": null, + "status": "success", + "tracking_company": "Amazon Logistics UK", + "tracking_number": "Sample001test", + "tracking_numbers": [ + "Sample001test" + ], + "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", + "tracking_urls": [ + "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530" + ], + "updated_at": "2022-01-05T18:16:48+05:30" }, - "billingAddress": { - "address1": "11 Rani Sankari Lane Patuapara Bhowanipore", - "address2": "", - "city": "Kolkata", - "company": null, - "country": "India", - "country_code": "IN", - "first_name": "Utsab", - "last_name": "Chowdhury", - "latitude": null, - "longitude": null, - "name": "Utsab Chowdhury", - "phone": null, - "province": "West Bengal", - "province_code": "WB", - "zip": "700025" + "output": { + "context": { + "library": { + "name": "RudderStack Shopify Cloud", + "version": "1.0.0" + }, + "integration": { + "name": "SHOPIFY" + }, + "topic": "fulfillments_update" + }, + "integrations": { + "SHOPIFY": true + }, + "type": "track", + "event": "Fulfillments Update", + "userId": "shopify-admin", + "properties": { + "admin_graphql_api_id": "gid://shopify/Fulfillment/4124667937024", + "created_at": "2022-01-05T18:13:02+05:30", + "destination": null, + "id": 4124667937024, + "location_id": 66855371008, + "name": "#1002.1", + "order_id": 4617255092480, + "origin_address": null, + "receipt": {}, + "service": "manual", + "shipment_status": null, + "status": "success", + "tracking_company": "Amazon Logistics UK", + "tracking_number": "Sample001test", + "tracking_numbers": [ + "Sample001test" + ], + "tracking_url": "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530", + "tracking_urls": [ + "https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=201910530" + ], + "updated_at": "2022-01-05T18:16:48+05:30", + "products": [ + { + "product_id": 7510929801472, + "sku": "15", + "title": "p1", + "price": "5000.00", + "brand": "rudderstack-store", + "quantity": 1, + "admin_graphql_api_id": "gid://shopify/LineItem/11896203149568", + "discount_allocations": [], + "duties": [], + "fulfillable_quantity": 0, + "fulfillment_service": "manual", + "fulfillment_status": "fulfilled", + "gift_card": false, + "grams": 0, + "id": 11896203149568, + "origin_location": { + "address1": "74 CC/7, Anupama Housing Estate - II", + "address2": "", + "city": "Kolkatta", + "country_code": "IN", + "id": 3373642219776, + "name": "74 CC/7, Anupama Housing Estate - II", + "province_code": "WB", + "zip": "700052" + }, + "price_set": { + "presentment_money": { + "amount": "5000.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "5000.00", + "currency_code": "INR" + } + }, + "product_exists": true, + "properties": [], + "requires_shipping": true, + "tax_lines": [ + { + "channel_liable": false, + "price": "900.00", + "price_set": { + "presentment_money": { + "amount": "900.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "900.00", + "currency_code": "INR" + } + }, + "rate": 0.18, + "title": "IGST" + } + ], + "taxable": true, + "total_discount": "0.00", + "total_discount_set": { + "presentment_money": { + "amount": "0.00", + "currency_code": "INR" + }, + "shop_money": { + "amount": "0.00", + "currency_code": "INR" + } + }, + "variant_inventory_management": "shopify", + "variant": "42211160228096 " + } + ] + }, + "traits": { + "email": "test_person@email.com", + "firstName": "Test", + "lastName": "Person", + "shippingAddress": { + "address1": "11 Rani Sankari Lane Patuapara Bhowanipore", + "address2": "", + "city": "Kolkata", + "company": null, + "country": "India", + "country_code": "IN", + "first_name": "Utsab", + "last_name": "Chowdhury", + "latitude": null, + "longitude": null, + "name": "Utsab Chowdhury", + "phone": null, + "province": "West Bengal", + "province_code": "WB", + "zip": "700025" + }, + "billingAddress": { + "address1": "11 Rani Sankari Lane Patuapara Bhowanipore", + "address2": "", + "city": "Kolkata", + "company": null, + "country": "India", + "country_code": "IN", + "first_name": "Utsab", + "last_name": "Chowdhury", + "latitude": null, + "longitude": null, + "name": "Utsab Chowdhury", + "phone": null, + "province": "West Bengal", + "province_code": "WB", + "zip": "700025" + } + } } - } } - } -] +] \ No newline at end of file diff --git a/test/__tests__/redisConnector.test.js b/test/__tests__/redisConnector.test.js deleted file mode 100644 index 2b4c5b289a..0000000000 --- a/test/__tests__/redisConnector.test.js +++ /dev/null @@ -1,55 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const version = "v0"; -const { RedisDB } = require('../../src/util/redisConnector'); -jest.mock('ioredis', () => require('../__mocks__/redis')); -const sourcesList = ['shopify'] -const destList = []; -process.env.USE_REDIS_DB = 'true'; -describe(`Source Tests`, () => { - sourcesList.forEach((source) => { - const testDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/redis/${source}_source.json`) - ); - const data = JSON.parse(testDataFile); - const transformer = require(`../../src/${version}/sources/${source}/transform`); - - data.forEach((dataPoint, index) => { - it(`${index}. ${source} - ${dataPoint.description}`, async () => { - try { - const output = await transformer.process(dataPoint.input); - expect(output).toEqual(dataPoint.output); - } catch (error) { - expect(error.message).toEqual(dataPoint.output.error); - } - }); - }); - }) -}); - -describe(`Redis Class Get Tests`, () => { - const testDataFile = fs.readFileSync( - path.resolve(__dirname, `./data/redis/redisConnector.json`) - ); - const data = JSON.parse(testDataFile); - data.forEach((dataPoint, index) => { - it(`${index}. Redis Get- ${dataPoint.description}`, async () => { - try { - const output = await RedisDB.getVal(dataPoint.input.value, false); - expect(output).toEqual(dataPoint.output); - } catch (error) { - expect(error.message).toEqual(dataPoint.output.error); - } - }); - }); -}); - -describe(`Redis Class Set Fail Test`, () => { - it(`Redis Set Fail Case Test`, async () => { - try { - await RedisDB.setVal("error", "test", false); - } catch (error) { - expect(error.message).toEqual("Error setting value in Redis due Error: Connection is Closed"); - } - }); -});