Skip to content

Commit

Permalink
chore: store sales updated, review comments addressed
Browse files Browse the repository at this point in the history
  • Loading branch information
shrouti1507 committed Mar 7, 2024
1 parent 602f57d commit bce1d62
Show file tree
Hide file tree
Showing 5 changed files with 503 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,10 @@ const getConversions = (message, metadata, { Config }, event, conversionType) =>
endpoint = STORE_CONVERSION_CONFIG.replace(':customerId', filteredCustomerId);
} else {
// call conversions
const consentObject = populateConsentForGoogleDestinations(message, conversionType, Config);
payload = constructPayload(message, trackCallConversionsMapping);
endpoint = CALL_CONVERSION.replace(':customerId', filteredCustomerId);
}
const consentObject = populateConsentForGoogleDestinations(message, conversionType);
if (Object.keys(consentObject)?.length > 0) {
if (payload?.conversions?.length > 0) {
if (conversionType === 'click' || conversionType === 'call') {
payload.conversions[0].consent = consentObject;
}
} else if (
Object.keys(payload?.addConversionPayload?.operations?.create)?.length > 0 &&
conversionType === 'store'
) {
payload.addConversionPayload.operations.create.consent = consentObject;
}
payload.conversions[0].consent = consentObject;
}

if (conversionType !== 'store') {
Expand Down
119 changes: 70 additions & 49 deletions src/v0/destinations/google_adwords_offline_conversions/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,72 @@ const {
const { processAxiosResponse } = require('../../../adapters/utils/networkUtils');
const Cache = require('../../util/cache');
const helper = require('./helper');
const {
GOOGLE_ALLOWED_CONSENT_STATUS,
UNKNOWN_CONSENT,
UNSPECIFIED_CONSENT,
} = require('../../util/googleUtils');

const conversionActionIdCache = new Cache(CONVERSION_ACTION_ID_CACHE_TTL);

/**
* Populates the consent object based on the provided properties.
*
* @param {object} properties - message.properties containing properties related to consent.
* @returns {object} - An object containing consent information.
* * ref :
* 1) For click conversion :
* a) https://developers.google.com/google-ads/api/rest/reference/rest/v15/customers/uploadClickConversions#ClickConversion
* b) https://developers.google.com/google-ads/api/reference/rpc/v15/ClickConversion#consent
* 2) For Call conversion :
* a) https://developers.google.com/google-ads/api/rest/reference/rest/v15/customers/uploadCallConversions#CallConversion
* b) https://developers.google.com/google-ads/api/reference/rpc/v15/CallConversion#consent
* 3) For Store sales conversion :
* a) https://developers.google.com/google-ads/api/reference/rpc/v15/UserData
* b) https://developers.google.com/google-ads/api/reference/rpc/v15/UserData#consent
*/

const populateConsentForGoogleDestinations = (message, conversionType, destConfig) => {
const integrationObj =
conversionType === 'store'
? {}
: getIntegrationsObj(message, 'GOOGLE_ADWORDS_OFFLINE_CONVERSIONS') || {};
const consents = integrationObj?.consents || {};

// Define a function to process consent based on type
const processConsent = (consentType) => {
// Access the default consent values from destConfig based on the consentType
let defaultConsentValue;
if (consentType === 'adUserData') {
defaultConsentValue = destConfig?.userDataConsent;
} else if (consentType === 'adPersonalization') {
defaultConsentValue = destConfig?.personalizationConsent;
} else {
defaultConsentValue = UNSPECIFIED_CONSENT;

Check warning on line 75 in src/v0/destinations/google_adwords_offline_conversions/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/google_adwords_offline_conversions/utils.js#L74-L75

Added lines #L74 - L75 were not covered by tests
}

if (!consents[consentType]) {
return defaultConsentValue || UNSPECIFIED_CONSENT;
}
if (GOOGLE_ALLOWED_CONSENT_STATUS.includes(consents[consentType])) {
return consents[consentType];

Check warning on line 82 in src/v0/destinations/google_adwords_offline_conversions/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/google_adwords_offline_conversions/utils.js#L82

Added line #L82 was not covered by tests
}
return defaultConsentValue || UNKNOWN_CONSENT;
};

// Common consent fields to process
const consentFields = ['adUserData', 'adPersonalization'];

// Construct consentObj based on the common consent fields
const consentObj = consentFields.reduce((obj, consentType) => {
// eslint-disable-next-line no-param-reassign
obj[consentType] = processConsent(consentType);
return obj;
}, {});

return consentObj;
};

/**
* validate destination config and check for existence of data
* @param {*} param0
Expand Down Expand Up @@ -273,6 +336,9 @@ const getAddConversionPayload = (message, Config) => {
set(payload, 'operations.create.userIdentifiers[0]', {});
}
}
// add consent support for store conversions
const consentObject = populateConsentForGoogleDestinations(message, 'store', Config);
set(payload, 'operations.create.consent', consentObject);
return payload;
};

Expand Down Expand Up @@ -360,56 +426,11 @@ const getClickConversionPayloadAndEndpoint = (message, Config, filteredCustomerI
if (!properties.conversionEnvironment && conversionEnvironment !== 'none') {
set(payload, 'conversions[0].conversionEnvironment', conversionEnvironment);
}
return { payload, endpoint };
};

const GOOGLE_ALLOWED_CONSENT_STATUS = ['UNSPECIFIED', 'UNKNOWN', 'GRANTED', 'DENIED'];

/**
* Populates the consent object based on the provided properties.
*
* @param {object} properties - message.properties containing properties related to consent.
* @returns {object} - An object containing consent information.
* * ref :
* 1) For click conversion :
* a) https://developers.google.com/google-ads/api/rest/reference/rest/v15/customers/uploadClickConversions#ClickConversion
* b) https://developers.google.com/google-ads/api/reference/rpc/v15/ClickConversion#consent
* 2) For Call conversion :
* a) https://developers.google.com/google-ads/api/rest/reference/rest/v15/customers/uploadCallConversions#CallConversion
* b) https://developers.google.com/google-ads/api/reference/rpc/v15/CallConversion#consent
* 3) For Store sales conversion :
* a) https://developers.google.com/google-ads/api/reference/rpc/v15/UserData
* b) https://developers.google.com/google-ads/api/reference/rpc/v15/UserData#consent
*/

const populateConsentForGoogleDestinations = (message) => {
const integrationObj = getIntegrationsObj(message, 'GOOGLE_ADWORDS_OFFLINE_CONVERSIONS') || {};
const consents = integrationObj.consents || {};

// Define a function to process consent based on type
const processConsent = (consentType) => {
if (!consents[consentType]) return 'UNSPECIFIED';
if (GOOGLE_ALLOWED_CONSENT_STATUS.includes(consents[consentType])) {
return consents[consentType];
}
return 'UNKNOWN';
};

// Common consent fields to process
const consentFields = {
adUserData: 'adUserData',
adPersonalization: 'adPersonalization',
};

// Construct consentObj based on the common consent fields
const consentObj = Object.keys(consentFields).reduce((obj, consentType) => {
const key = consentFields[consentType];
// eslint-disable-next-line no-param-reassign
obj[key] = processConsent(consentType);
return obj;
}, {});

return consentObj;
// add consent support for click conversions
const consentObject = populateConsentForGoogleDestinations(message, 'click', Config);
set(payload, 'conversions[0].consent', consentObject);
return { payload, endpoint };
};

module.exports = {
Expand Down
109 changes: 106 additions & 3 deletions src/v0/destinations/google_adwords_offline_conversions/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => {
{
conversionDateTime: '2022-01-01 12:32:45-08:00',
conversionEnvironment: 'WEB',
consent: {
adPersonalization: 'UNSPECIFIED',
adUserData: 'UNSPECIFIED',
},
userIdentifiers: [
{
hashedEmail: 'fa922cb41ff930664d4c9ced3c472ce7ecf29a0f8248b7018456e990177fff75',
Expand All @@ -193,6 +197,10 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => {
conversions: [
{
conversionDateTime: '2022-01-01 12:32:45-08:00',
consent: {
adPersonalization: 'UNSPECIFIED',
adUserData: 'UNSPECIFIED',
},
conversionEnvironment: 'WEB',
userIdentifiers: [
{
Expand Down Expand Up @@ -259,6 +267,10 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => {
cartData: { items: [{ productId: 1234, quantity: 2, unitPrice: 10 }] },
conversionDateTime: '2022-01-01 12:32:45-08:00',
conversionEnvironment: 'WEB',
consent: {
adPersonalization: 'UNSPECIFIED',
adUserData: 'UNSPECIFIED',
},
userIdentifiers: [
{
hashedEmail: 'fa922cb41ff930664d4c9ced3c472ce7ecf29a0f8248b7018456e990177fff75',
Expand All @@ -277,7 +289,7 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => {

describe('populateConsentForGoogleDestinations', () => {
// Returns an object with adUserData and adPersonalization properties set to UNSPECIFIED when no consents are provided
it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS : store sales conversion without any mention in integrations object', () => {
it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS : store sales conversion without consent related field in destination config', () => {
const message = {};
const conversionType = 'store';

Expand All @@ -289,8 +301,7 @@ describe('populateConsentForGoogleDestinations', () => {
});
});

// Returns an empty object when the destination name is not recognized
it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS: store sales conversions with integrations object', () => {
it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS: store sales conversions with integrations object but without consent fields in config', () => {
const message = {
integrations: {
google_adwords_offline_conversions: {
Expand All @@ -305,6 +316,32 @@ describe('populateConsentForGoogleDestinations', () => {

const result = populateConsentForGoogleDestinations(message, conversionType);

expect(result).toEqual({
adPersonalization: 'UNSPECIFIED',
adUserData: 'UNSPECIFIED',
});
});

it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS: store sales conversions with integrations object along with consent fields in config', () => {
const message = {
integrations: {
google_adwords_offline_conversions: {
consents: {
adUserData: 'GRANTED',
adPersonalization: 'DENIED',
},
},
},
};
const conversionType = 'store';

const destConfig = {
userDataConsent: 'GRANTED',
personalizationConsent: 'DENIED',
};

const result = populateConsentForGoogleDestinations(message, conversionType, destConfig);

expect(result).toEqual({
adPersonalization: 'DENIED',
adUserData: 'GRANTED',
Expand Down Expand Up @@ -367,4 +404,70 @@ describe('populateConsentForGoogleDestinations', () => {
adPersonalization: 'UNSPECIFIED',
});
});

it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS : click conversion without integrations', () => {
const message = {
integrations: {
google_adwords_offline_conversions: {},
},
};
const conversionType = 'click';

const destConfig = {
userDataConsent: 'GRANTED',
personalizationConsent: 'DENIED',
};

const result = populateConsentForGoogleDestinations(message, conversionType, destConfig);

expect(result).toEqual({
adUserData: 'GRANTED',
adPersonalization: 'DENIED',
});
});

it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS : click conversion without integrations and UI config has partial data', () => {
const message = {
integrations: {
google_adwords_offline_conversions: {},
},
};
const conversionType = 'click';

const destConfig = {
userDataConsent: 'GRANTED',
};

const result = populateConsentForGoogleDestinations(message, conversionType, destConfig);

expect(result).toEqual({
adUserData: 'GRANTED',
adPersonalization: 'UNSPECIFIED',
});
});

it('GOOGLE_ADWORDS_OFFLINE_CONVERSIONS : click conversion with partial data present in integrations object', () => {
const message = {
integrations: {
google_adwords_offline_conversions: {
consents: {
adUserData: 'GRANTED',
},
},
},
};

const destConfig = {
userDataConsent: 'GRANTED',
personalizationConsent: 'DENIED',
};
const conversionType = 'click';

const result = populateConsentForGoogleDestinations(message, conversionType, destConfig);

expect(result).toEqual({
adUserData: 'GRANTED',
adPersonalization: 'DENIED',
});
});
});
10 changes: 9 additions & 1 deletion src/v0/util/googleUtils/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
const GOOGLE_ALLOWED_CONSENT_STATUS = ['UNSPECIFIED', 'UNKNOWN', 'GRANTED', 'DENIED'];

const UNSPECIFIED_CONSENT = 'UNSPECIFIED';
const UNKNOWN_CONSENT = 'UNKNOWN';

/**
* Populates the consent object based on the provided properties.
*
Expand Down Expand Up @@ -33,4 +36,9 @@ const populateConsentForGoogleDestinations = (config) => {
return consent;
};

module.exports = { populateConsentForGoogleDestinations };
module.exports = {
populateConsentForGoogleDestinations,
UNSPECIFIED_CONSENT,
UNKNOWN_CONSENT,
GOOGLE_ALLOWED_CONSENT_STATUS,
};
Loading

0 comments on commit bce1d62

Please sign in to comment.