Skip to content

Commit

Permalink
feat: onboard new destination rakuten_advertising
Browse files Browse the repository at this point in the history
  • Loading branch information
anantjain45823 committed Jan 31, 2024
1 parent db2c170 commit a42bef3
Show file tree
Hide file tree
Showing 9 changed files with 1,068 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/cdk/v2/destinations/rakuten/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const { getMappingConfig } = require('../../../../v0/util');

const ConfigCategories = {
TRACK: {
type: 'track',
name: 'propertiesMapping',
},
};
const mappingConfig = getMappingConfig(ConfigCategories, __dirname);
// Following contains the keys at item level mapping where key can be considered as destkey and value can be considered as sourcekey
const productProperties = {
skulist: 'sku',
qlist: 'quantity',
namelist: 'name',
brandlist: 'brand',
couponlist: 'coupon',
catidlist: 'categoryId',
catlist: 'category',
disamtlist: 'discountAmount',
distypelist: 'discountType',
isclearancelist: 'isClearance',
ismarketplacelist: 'isMarketPlace',
issalelist: 'isSale',
itmstatuslist: 'itmStatus',
marginlist: 'margin',
markdownlist: 'markdown',
shipidlist: 'shipId',
shipbylist: 'shipBy',
taxexemptlist: 'taxExempt',
sequencelist: 'sequence',
};
module.exports = { ConfigCategories, mappingConfig, productProperties };
101 changes: 101 additions & 0 deletions src/cdk/v2/destinations/rakuten/data/propertiesMapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
[
{
"sourceKeys": "properties.orderId",
"required": true,
"destKey": "ord"
},
{
"sourceKeys": ["properties.tr", "properties.ranSiteID"],
"required": true,
"destKey": "tr"
},
{
"sourceKeys": ["properties.land", "properties.landTime"],
"required": true,
"destKey": "land"
},
{
"sourceKeys": ["properties.date", "properties.orderCompletedTime"],
"destKey": "date"
},
{
"sourceKeys": ["properties.altord", "properties.alterOrderId"],
"destKey": "altord"
},
{
"sourceKeys": "properties.currency",
"destKey": "cur"
},
{
"sourceKeys": "properties.creditCardType",
"destKey": "cc"
},
{
"sourceKeys": "properties.commReason",
"destKey": "commreason"
},
{
"sourceKeys": "properties.isComm",
"destKey": "iscomm"
},
{
"sourceKeys": "properties.consumed",
"destKey": "consumed"
},
{
"sourceKeys": "properties.coupon",
"destKey": "coupon"
},
{
"sourceKeys": ["properties.custId", "properties.customerId", "properties.userId"],
"destKey": "custid"
},
{
"sourceKeys": ["properties.custScore", "properties.customerScore"],
"destKey": "custscore"
},
{
"sourceKeys": ["properties.custStatus", "properties.customerStatus"],
"destKey": "custstatus"
},
{
"sourceKeys": ["properties.dId", "properties.advertisingId"],
"destKey": "did"
},
{
"sourceKeys": ["properties.disamt", "properties.discountAmout"],
"destKey": "disamt"
},
{
"sourceKeys": ["properties.ordStatus", "properties.orderStatus"],
"destKey": "ordstatus"
},
{
"sourceKeys": "properties.segment",
"destKey": "segment"
},
{
"sourceKeys": "properties.shipcountry",
"destKey": "shipcountry"
},
{
"sourceKeys": "properties.shipped",
"destKey": "shipped"
},
{
"sourceKeys": "properties.sitename",
"destKey": "sitename"
},
{
"sourceKeys": "properties.storeId",
"destKey": "storeid"
},
{
"sourceKeys": ["properties.storecat", "properties.storeCategory"],
"destKey": "storecat"
},
{
"sourceKeys": "properties.currency",
"destKey": "cur"
}
]
41 changes: 41 additions & 0 deletions src/cdk/v2/destinations/rakuten/procWorkflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
bindings:
- name: EventType
path: ../../../../constants
- path: ../../bindings/jsontemplate
- name: defaultRequestConfig
path: ../../../../v0/util
- name: removeUndefinedAndNullValues
path: ../../../../v0/util
- path: ./utils

steps:
- name: messageType
template: |
.message.type.toLowerCase();
- name: validateInput
template: |
let messageType = $.outputs.messageType;
$.assert(messageType, "message Type is not present. Aborting");
$.assert(messageType in {{$.EventType.([.TRACK])}}, "message type " + messageType + " is not supported");
$.assertConfig(.destination.Config.mid, "Merchant ID is not present. Aborting");
- name: prepareTrackPayload
condition: $.outputs.messageType === {{$.EventType.TRACK}}
template: |
const properties = $.constructProperties(.message);
const lineItems = $.constructLineItems(.message.properties)
$.context.payload = {...properties,...lineItems,xml:1, mid:.destination.Config.mid}
$.context.payload = $.removeUndefinedAndNullValues($.context.payload);
- name: buildResponse
template: |
console.log("$.context.payload2",$.context.payload)
const response = $.defaultRequestConfig();
response.params = $.context.payload;
response.method = "GET";
response.endpoint = "https://track.linksynergy.com/ep";
response.headers = {
"accept": "application/json",
"content-type": "application/json"
};
console.log("responseBidy",response)
response
47 changes: 47 additions & 0 deletions src/cdk/v2/destinations/rakuten/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const { InstrumentationError } = require('@rudderstack/integrations-lib');
const { mappingConfig, ConfigCategories, productProperties } = require('./config');
const { constructPayload } = require('../../../../v0/util');

/**
* This fucntion constructs payloads based upon mappingConfig for Track call type
* @param {*} message
* @returns
*/
const constructProperties = (message) => {
const payload = constructPayload(message, mappingConfig[ConfigCategories.TRACK.name]);
return payload;
};

/**
* This fucntion build the item level list
* @param {*} properties
* @returns
*/
const constructLineItems = (properties) => {
if (!Array.isArray(properties?.products) || properties?.products.length < 1) {
throw new InstrumentationError('Either properties.product is not an array or is empty');
}
const productList = {};
// mapping all the properties leaving amount as for amount we need to do some calculations
Object.keys(productProperties).forEach((property) => {
const propertyKey = productProperties[property];
const values = properties.products.map((product) => product?.[propertyKey] || '');
if (values.some((element) => element !== '')) {
productList[property] = values.join('|');
}
});
// mapping amount list
const amountList = properties.products.map((product) => {
if (!product.amount) {
if (product?.price) {
return (product.quantity || 1) * product.price * 100;
}
throw new InstrumentationError('Either amount or price is required for every product');
}
return product.amount * 100;
});
productList.amtlist = amountList.join('|');
return productList;
};

module.exports = { constructProperties, constructLineItems };
98 changes: 98 additions & 0 deletions src/cdk/v2/destinations/rakuten/utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const { constructLineItems } = require('./utils');
describe('constructLineItems', () => {
it('should return a non-empty object when given a valid properties object with at least one product', () => {
const properties = {
products: [
{
name: 'Product 1',
price: 10,
quantity: 2,
amount: 20,
},
],
};
const result = constructLineItems(properties);
const expectedObj = {
namelist: 'Product 1',
qlist: '2',
amtlist: '2000',
};
expect(result).toEqual(expectedObj);
});

it('should include all mapped properties in the returned object when present in at least one product', () => {
const properties = {
products: [
{
name: 'Product 1',
category: 'Category 1',
brand: 'Brand 1',
price: 10,
quantity: 2,
amount: 20,
},
],
};

const result = constructLineItems(properties);

const expectedObj = {
namelist: 'Product 1',
catlist: 'Category 1',
brandlist: 'Brand 1',
qlist: '2',
amtlist: '2000',
};
expect(result).toEqual(expectedObj);
});

it('should include amtlist property in the returned object with calculated values', () => {
const properties = {
products: [
{
name: 'Product 1',
price: 10,
quantity: 2,
},
{
name: 'Product 2',
price: 5,
quantity: 3,
},
],
};

const result = constructLineItems(properties);

expect(result).toHaveProperty('amtlist');
expect(result.amtlist).toBe('2000|1500');
});

it('should throw an InstrumentationError when properties object is missing or has an empty products array', () => {
const properties = {};

expect(() => constructLineItems(properties)).toThrow(
'Either properties.product is not an array or is empty',
);

properties.products = [];

expect(() => constructLineItems(properties)).toThrow(
'Either properties.product is not an array or is empty',
);
});

it('should throw an InstrumentationError when a product is missing both amount and price/quantity properties', () => {
const properties = {
products: [
{
name: 'Product 1',
},
],
};

expect(() => constructLineItems(properties)).toThrow(
'Either amount or price is required for every product',
);
});
});
65 changes: 65 additions & 0 deletions test/integrations/destinations/rakuten/processor/commonConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
export const destination = {
ID: 'random_id',
Name: 'rakuten',
DestinationDefinition: {
Config: {
cdkV2Enabled: true,
},
},
Config: {
mid: 'dummyMarketingId',
},
};
export const endpoint = 'https://track.linksynergy.com/ep';
export const commonOutputHeaders = {
accept: 'application/json',
'content-type': 'application/json',
};
export const singleProductWithAllProperties = {
sku: 'ABC123',
amount: 20,
quantity: 5,
name: 'SampleProduct',
brand: 'SampleBrand',
coupon: 'SALE20',
categoryId: '12345',
category: 'Electronics',
discountAmount: 10.5,
discountType: 'Percentage',
isClearance: 'Y',
isMarketPlace: 'N',
isSale: 'Y',
itmStatus: 'In Stock',
margin: 0.15,
markdown: 5.0,
shipId: 'SHIP123',
shipBy: 'Express',
taxExempt: 'N',
sequence: '123',
isComm: 'Y',
};
export const commonProperties = {
orderId: 'SampleOrderId',
tr: 'SampleRanSiteID',
landTime: '20240129_1200',
date: '20240129_1300',
altord: 'SampleAlternateOrderId',
currency: 'INR',
creditCardType: 'Visa',
commReason: 'SampleCommReason',
isComm: 'Y',
consumed: '20240129_1400',
coupon: 'SampleCoupon',
custId: 'SampleCustomerId',
custScore: 'A',
custStatus: 'New',
dId: 'SampleDeviceId',
disamt: '50.00',
ordStatus: 'Pending',
segment: 'SampleSegment',
shipcountry: 'USA',
shipped: '20240129_1500',
sitename: 'SampleSiteName',
storeId: '12345',
storecat: 'Electronics',
};
3 changes: 3 additions & 0 deletions test/integrations/destinations/rakuten/processor/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { transformationFailures } from './transformationFailure';
import { trackSuccess } from './track';
export const data = [...trackSuccess, ...transformationFailures];
Loading

0 comments on commit a42bef3

Please sign in to comment.