Skip to content

Commit

Permalink
feat(analytics|react): update order completed analytics event
Browse files Browse the repository at this point in the history
- update fields on `order_completed` event contract of
GA4 and Omnitracking integration to add new fields.
  • Loading branch information
danielbento92 authored and boliveira committed May 23, 2023
1 parent aae0757 commit cb1ee2a
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ Object {
"LOAD_INTEGRATION_TRACK_TYPE": "loadIntegration",
"ON_SET_USER_TRACK_TYPE": "onSetUser",
"StorageWrapper": [Function],
"getCheckoutOrderIdentificationProperties": [Function],
"getCheckoutProperties": [Function],
"getContextDefaults": [Function],
"getCookie": [Function],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ describe('Omnitracking', () => {
await omnitracking.track(data);

data = generateTrackMockData({
event: EventType.PlaceOrderStarted,
event: EventType.Share,
});
await omnitracking.track(data);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,12 @@ Object {

exports[`Omnitracking track events definitions \`Order Completed\` return should match the snapshot 1`] = `
Object {
"addressFinder": false,
"checkoutOrderId": 21312312,
"checkoutStep": 5,
"deliveryInformationDetails": "{\\"deliveryType\\":\\"Standard/Standard\\",\\"courierType\\":\\"Next Day\\",\\"packagingType\\":\\"foo\\"}",
"orderCode": "ABC12",
"paymentType": "credit card",
"tid": 2831,
}
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,10 @@ export const trackEventsMapper: Readonly<OmnitrackingTrackEventsMapper> = {
[EventType.OrderCompleted]: data => ({
tid: 2831,
...getCheckoutEventGenericProperties(data),
addressFinder: data.properties?.addressFinder,
checkoutStep: data.properties?.step,
paymentType: data.properties?.paymentType,
deliveryInformationDetails: getDeliveryInformationDetails(data),
}),
[EventType.Logout]: () => ({
tid: 431,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ANALYTICS_UNIQUE_EVENT_ID } from '../../utils/constants.js';
import {
ANALYTICS_UNIQUE_EVENT_ID,
getCheckoutOrderIdentificationProperties,
getProductId,
logger,
} from '../../utils/index.js';
import {
type AnalyticsProduct,
type EventData,
Expand All @@ -12,7 +17,6 @@ import {
DEFAULT_SEARCH_QUERY_PARAMETERS,
} from './constants.js';
import { get, pick } from 'lodash-es';
import { getProductId, logger } from '../../utils/index.js';
import {
isPageEventType,
isScreenEventType,
Expand Down Expand Up @@ -522,19 +526,19 @@ export const getProductLineItems = (data: EventData<TrackTypesValues>) => {
export const getCheckoutEventGenericProperties = (
data: EventData<TrackTypesValues>,
) => {
const validOrderCode = isNaN(Number(data.properties?.orderId));
const orderInfo = getCheckoutOrderIdentificationProperties(data.properties);

if (!validOrderCode) {
if (orderInfo.orderCode === undefined) {
logger.error(
`[Omnitracking] - Event ${data.event} property "orderId" should be an alphanumeric value.
If you send the internal "orderId", please use "orderId" (e.g.: 5H5QYB)
If you want to send the internal "orderId", please use "orderId" (e.g.: 5H5QYB)
and 'checkoutOrderId' (e.g.:123123123)`,
);
}

return {
orderCode: data.properties?.orderId,
checkoutOrderId: data.properties?.checkoutOrderId,
orderCode: orderInfo.orderCode,
checkoutOrderId: orderInfo.orderId,
};
};

Expand Down
99 changes: 99 additions & 0 deletions packages/analytics/src/utils/__tests__/getters.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import * as getters from '../getters.js';

describe('getters', () => {
describe('getCheckoutOrderIdentificationProperties', () => {
it('Should retrieve order data with multiple test cases', () => {
const checkoutOrderId = 123;

expect(
getters.getCheckoutOrderIdentificationProperties({
orderId: null,
checkoutOrderId: checkoutOrderId,
}),
).toEqual({
orderCode: undefined,
orderId: checkoutOrderId,
});

expect(
getters.getCheckoutOrderIdentificationProperties({
orderId: undefined,
checkoutOrderId: checkoutOrderId,
}),
).toEqual({
orderCode: undefined,
orderId: checkoutOrderId,
});

expect(
getters.getCheckoutOrderIdentificationProperties({
orderId: 0,
checkoutOrderId: checkoutOrderId,
}),
).toEqual({
orderCode: undefined,
orderId: checkoutOrderId,
});

expect(
getters.getCheckoutOrderIdentificationProperties({
orderId: '0',
checkoutOrderId: checkoutOrderId,
}),
).toEqual({
orderCode: undefined,
orderId: checkoutOrderId,
});

expect(
getters.getCheckoutOrderIdentificationProperties({
orderId: 12345,
checkoutOrderId: checkoutOrderId,
}),
).toEqual({
orderCode: undefined,
orderId: checkoutOrderId,
});

expect(
getters.getCheckoutOrderIdentificationProperties({
orderId: '12345',
checkoutOrderId: checkoutOrderId,
}),
).toEqual({
orderCode: undefined,
orderId: checkoutOrderId,
});

expect(
getters.getCheckoutOrderIdentificationProperties({
orderId: 'A12345',
checkoutOrderId: checkoutOrderId,
}),
).toEqual({
orderCode: 'A12345',
orderId: checkoutOrderId,
});

expect(
getters.getCheckoutOrderIdentificationProperties({
orderId: NaN,
checkoutOrderId: checkoutOrderId,
}),
).toEqual({
orderCode: undefined,
orderId: checkoutOrderId,
});

expect(
getters.getCheckoutOrderIdentificationProperties({
orderId: 123,
checkoutOrderId: undefined,
}),
).toEqual({
orderCode: undefined,
orderId: 123,
});
});
});
});
41 changes: 41 additions & 0 deletions packages/analytics/src/utils/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,44 @@ export const getCookie = (name: string): string | void => {
return parts.pop()?.split(';').shift();
}
};

/**
* Obtain checkout order generic fields from analytics properties.
*
* @param dataProperties - The event's properties data.
* @param orderIdFieldName - The name of orderId field. Default as `checkoutOrderId`.
* @returns The checkout generic order data result.
*/
export const getCheckoutOrderIdentificationProperties = (
eventProperties: EventProperties,
) => {
const checkoutOrderId = eventProperties?.checkoutOrderId;
const orderId = eventProperties?.orderId;
const orderIdAsNumber = Number(orderId);
// Valid order code should be an alphanumeric value.
// Should be used 'orderId' values like e.g.: 5H5QYB
// and for 'checkoutOrderId' values like e.g.:123123123
const isOrderCodeValid =
typeof orderId === 'string' && isNaN(orderIdAsNumber);
const isOrderIdValid =
typeof checkoutOrderId === 'number' && !isNaN(checkoutOrderId);

const orderCode = isOrderCodeValid ? orderId : undefined;

let finalOrderId;

// If we have a valid order id, i.e., the property checkoutOrderId from the
// event properties is a number, then we always use it.
if (isOrderIdValid) {
finalOrderId = checkoutOrderId;
} else if (!isOrderCodeValid) {
// If we do not have a valid order code and checkoutOrderId is not valid
// we use the orderId from the payload if it is not NaN
finalOrderId = !isNaN(orderIdAsNumber) ? orderIdAsNumber : undefined;
}

return {
orderCode,
orderId: finalOrderId,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,13 @@ Array [
"purchase",
Object {
"__blackoutAnalyticsEventId": "4eabf689-96e3-4952-8176-248a848f1e1f",
"address_finder": false,
"affiliation": undefined,
"analytics_package_version": "0.1.0",
"checkout_step": 5,
"coupon": "ACME2019",
"currency": "USD",
"delivery_type": "Standard/Standard",
"items": Array [
Object {
"affiliation": undefined,
Expand All @@ -498,9 +501,12 @@ Array [
"size": "L",
},
],
"packaging_type": "foo",
"page_path": "/en-pt/?utm_term=utm_term&utm_source=utm_source&utm_medium=utm_medium&utm_content=utm_content&utm_campaign=utm_campaign",
"path_clean": "/en-pt/",
"payment_type": "credit card",
"shipping": 3.6,
"shipping_tier": "Next Day",
"tax": 2.04,
"transaction_id": "ABC12",
"value": 24.64,
Expand Down
34 changes: 32 additions & 2 deletions packages/react/src/analytics/integrations/GA4/eventMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ const getLoginAndSignupParametersFromEvent = (
*
* @returns Properties formatted for the GA4's order completed/refunded ecommerce events.
*/
const getOrderPurchaseOrRefundParametersFromEvent = (
const getOrderPurchaseOrRefundGenericParametersFromEvent = (
eventProperties: EventProperties,
) => {
return {
Expand All @@ -584,6 +584,33 @@ const getOrderPurchaseOrRefundParametersFromEvent = (
};
};

/**
* Returns the checkout order completed event properties formatted for the GA4 ecommerce events with some custom parameters.
*
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/ecommerce#purchases_checkouts_and_refunds}
*
* @param eventProperties - Properties from a track event.
*
* @returns Properties formatted for the GA4's order completed/refunded ecommerce events.
*/
const getOrderPurchaseParametersFromEvent = (
eventProperties: EventProperties,
) => {
const orderInfo =
utils.getCheckoutOrderIdentificationProperties(eventProperties);

return {
...getOrderPurchaseOrRefundGenericParametersFromEvent(eventProperties),
address_finder: eventProperties.addressFinder,
checkout_step: eventProperties.step,
delivery_type: eventProperties.deliveryType,
payment_type: eventProperties.paymentType,
packaging_type: eventProperties.packagingType,
shipping_tier: eventProperties.shippingTier,
transaction_id: orderInfo.orderCode,
};
};

/**
* Returns the place order started custom event properties formatted for the GA4
* ecommerce events. As it returns the same properties of a purchase event, it uses
Expand Down Expand Up @@ -844,8 +871,11 @@ export function getEventProperties(
return getViewItemParametersFromEvent(eventProperties);

case EventType.OrderCompleted:
return getOrderPurchaseParametersFromEvent(eventProperties);
case EventType.OrderRefunded:
return getOrderPurchaseOrRefundParametersFromEvent(eventProperties);
return getOrderPurchaseOrRefundGenericParametersFromEvent(
eventProperties,
);

case PageType.Search:
return getSearchParametersFromEvent(eventProperties);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ const fixtures = {
tax: 2.04,
coupon: 'ACME2019',
currency: 'USD',
addressFinder: false,
step: 5,
deliveryType: 'Standard/Standard',
packagingType: 'foo',
shippingTier: 'Next Day',
paymentType: 'credit card',
products: [
{
id: '507f1f77bcf86cd799439011',
Expand Down

0 comments on commit cb1ee2a

Please sign in to comment.