Merge pull request #1984 from Safelite/feature/Digital/CSR-1629

CSR-1629
This commit is contained in:
hiteshkumar87 2024-09-19 20:53:35 +05:30 committed by GitHub
commit d7c3d64f7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 461 additions and 0 deletions

View file

@ -384,6 +384,235 @@ export default {
});
},
pushProductArrayToDataLayer() {
// Get correct order object
const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
const submittedOrder = baseMixin.methods.getSubmittedOrder();
if (hasSubmittedOrder) {
var lineItems = submittedOrder.lineItems ? submittedOrder.lineItems : {};
// combine all line items
var combinedLineItems = [
...(lineItems.glassParts ?? []),
...(lineItems.supportingItems ?? []),
...(lineItems.vaps ?? []),
...(lineItems.promos ?? []),
];
//Get child parts
combinedLineItems = flattenArray(combinedLineItems);
var products = [];
var discount = 0;
var coupon = "";
var subTotal = 0;
for (var i = 0; i < combinedLineItems.length; i++) {
let part = combinedLineItems[i];
let productSku = part.partNumber;
let productType = part.partType;
let promoCode = part.promoCode;
let productPrice = baseMixin.methods
.getTotalPriceOfAllLineItemsAndChildParts([part], false)
.toFixed(2);
if (productSku == "DISCOUNT") {
if (coupon) {
coupon += ",";
}
coupon += productSku;
discount = discount + parseFloat(productPrice) * -1;
} else {
products.push({
productType: productType,
productSku: productSku,
productPrice: productPrice.toString(),
productQuantity: "1",
});
subTotal += parseFloat(productPrice);
}
}
pushToDataLayerIfDefined({
productArray: {
coupon: coupon,
discount: discount.toString(),
subTotal: subTotal.toString(),
products: products,
},
});
}
},
pushECommerceCartToDataLayer() {
const isDefined = (x) => x !== null && x !== undefined;
// Get correct order object
const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
const submittedOrder = baseMixin.methods.getSubmittedOrder();
if (hasSubmittedOrder) {
var lineItems = submittedOrder.lineItems ? submittedOrder.lineItems : {};
var supportingItems =
submittedOrder.lineItems && submittedOrder.lineItems.supportingItems
? submittedOrder.lineItems.supportingItems
: [];
var insurance = submittedOrder.payment && submittedOrder.payment.isInsurance;
var itac = submittedOrder.policy && submittedOrder.policy.isItac;
var nocomp = submittedOrder.policy && submittedOrder.policy.isNoComp;
var recalLineItem = supportingItems.filter(function (lineItem) {
return lineItem.partType.indexOf("RECALIBRATION") !== -1;
});
var disposalFee = supportingItems.filter(function (lineItem) {
return lineItem.partType.indexOf("DISPOSAL FEE") !== -1;
});
var mobileFee = supportingItems.filter(function (lineItem) {
return lineItem.partType.indexOf("MOBILE FEE") !== -1;
});
var repairFee = supportingItems.filter(function (lineItem) {
return lineItem.partType.indexOf("REPAIR FEE") !== -1;
});
var vaps =
submittedOrder.lineItems && submittedOrder.lineItems.vaps
? submittedOrder.lineItems.vaps
: [];
var wipers = vaps.filter(function (lineItem) {
return (
lineItem.partType.indexOf("FRONT WIPER") !== -1 ||
lineItem.partType.indexOf("REAR WIPER") !== -1
);
});
var rainDefense = vaps.filter(function (lineItem) {
return lineItem.partType.indexOf("RAIN DEFENSE") !== -1;
});
// Combine line items
var combinedLineItems = [];
if (lineItems.glassParts) {
combinedLineItems = combinedLineItems.concat(lineItems.glassParts);
}
if (recalLineItem) {
combinedLineItems = combinedLineItems.concat(recalLineItem);
}
if (disposalFee) {
combinedLineItems = combinedLineItems.concat(disposalFee);
}
if (mobileFee && !(insurance && !itac && !nocomp)) {
combinedLineItems = combinedLineItems.concat(mobileFee);
}
if (repairFee) {
combinedLineItems = combinedLineItems.concat(repairFee);
}
if (wipers) {
combinedLineItems = combinedLineItems.concat(wipers);
}
if (rainDefense) {
combinedLineItems = combinedLineItems.concat(rainDefense);
}
//Remove child Parts if any
combinedLineItems.forEach((lineItem) => {
lineItem.childParts = [];
});
var isPricingAvailable =
combinedLineItems.length > 0 &&
combinedLineItems.every(function (lineItem) {
return (
isDefined(lineItem.kitPrice) &&
isDefined(lineItem.laborAmount) &&
isDefined(lineItem.sellingPrice)
);
});
let subtotal = 0;
if (isPricingAvailable) {
subtotal = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
combinedLineItems,
false
);
}
pushToDataLayerIfDefined({
eCommerceCart: { products: combinedLineItems, subTotal: parseInt(subtotal) },
});
}
},
pushCommissionJunctionGtmDataToDataLayer() {
// helper check for if an object is defined (but maybe falsey)
const isDefined = (x) => x !== null && x !== undefined;
let repairReplace = "";
let coupons = "";
let refSequenceNum = "";
let accountType = "";
let amount = 0;
let cjEvent = "";
if (store.getters.applicationUser.affiliateCookies) {
const affiliateCookies = store.getters.applicationUser.affiliateCookies;
var cookieArray = [];
affiliateCookies.forEach((item) => {
let cookieObject = convertCookieStringToObject(item.CookieValue);
cookieArray.push(cookieObject);
});
const sortedCookies = cookieArray.sort(
(a, b) =>
new Date(b.timestamp.replace("/", "T")) -
new Date(a.timestamp.replace("/", "T"))
);
cjEvent = sortedCookies?.[0]?.tagEvent;
const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
const submittedOrder = baseMixin.methods.getSubmittedOrder();
if (hasSubmittedOrder) {
repairReplace = submittedOrder.damage.isRepair ? "Repair" : "Replace";
const promos = submittedOrder.lineItems.promos ?? [];
if (promos.length === 0) {
coupons = "";
} else {
const promoCodes = promos.map((promo) => promo.promoCode);
const promoString = promoCodes.reduce((prev, next) => `${prev}_${next}`);
coupons = promoString;
}
refSequenceNum = submittedOrder.referralSequenceNumber;
if (isDefined(submittedOrder.payment.isInsurance)) {
accountType = submittedOrder.payment.isInsurance ? "insurance" : "cash";
} else {
accountType = "";
}
const lineItems = submittedOrder.lineItems ?? {};
const combinedLineItems = [
...(lineItems.glassParts ?? []),
...(lineItems.supportingItems ?? []),
...(lineItems.vaps ?? []),
...(lineItems.promos ?? []),
];
const isPricingAvailable =
combinedLineItems.length > 0 &&
combinedLineItems.every(
(lineItem) =>
isDefined(lineItem.kitPrice) &&
isDefined(lineItem.laborAmount) &&
isDefined(lineItem.sellingPrice)
);
if (accountType == "cash" && isPricingAvailable) {
const quoteAmountWithDiscount = baseMixin.methods
.getTotalPriceOfAllLineItemsAndChildParts(combinedLineItems, false)
.toFixed(2);
amount = parseFloat(quoteAmountWithDiscount);
}
}
}
pushToDataLayerIfDefined({
commissionJunctionGtmData: {
cj_commission_junction_event: cjEvent,
cj_referral_sequence_number: refSequenceNum,
cj_amount: amount.toString(),
cj_repair_replace: repairReplace,
cj_coupon: coupons,
},
});
},
prependActionToMethod(object, method, actionToPrepend) {
const baseMethodName = method.name.startsWith("bound ")
? method.name.substring(6)
@ -496,3 +725,24 @@ function getValueToLog(value, valueToLogType) {
}
return value;
}
function flattenArray(arr) {
let result = [];
arr.forEach((item) => {
result.push(item);
if (item.childParts) {
result = result.concat(item.childParts);
delete item.childParts; // Remove childParts after flattening
}
});
return result;
}
function convertCookieStringToObject(cookieValue) {
const cookieObject = cookieValue.split("&").reduce((acc, pair) => {
const [key, value] = pair.split("=");
acc[key] = value;
return acc;
}, {});
return cookieObject;
}

View file

@ -853,4 +853,198 @@ describe("analyticsMixin.js", () => {
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
});
});
describe("push product array and ecommerce cart to data layer", () => {
const mocks = setupMocksForJsFiles();
it("should push product array to data layer correctly", () => {
// Mock the methods
mocks.baseMixin.methods.hasSubmittedOrder = jest.fn();
mocks.baseMixin.methods.getSubmittedOrder = jest.fn();
mocks.baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts = jest.fn();
mocks.baseMixin.methods.hasSubmittedOrder.mockReturnValue(true);
mocks.baseMixin.methods.getSubmittedOrder.mockReturnValue({
lineItems: {
glassParts: [{ partNumber: "GP1", partType: "glass" }],
supportingItems: [{ partNumber: "SI1", partType: "support" }],
vaps: [{ partNumber: "VAP1", partType: "vap" }],
promos: [{ partNumber: "DISCOUNT", partType: "promo", promoCode: "PROMO4" }],
},
});
mocks.baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts.mockReturnValue(100);
// Call the function
analyticsMixin.methods.pushProductArrayToDataLayer();
// Assertions
expect(mocks.baseMixin.methods.hasSubmittedOrder).toHaveBeenCalled();
expect(mocks.baseMixin.methods.getSubmittedOrder).toHaveBeenCalled();
expect(
mocks.baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts
).toHaveBeenCalled();
});
it("should push eCommerce cart to data layer correctly", () => {
// Mock the methods
mocks.baseMixin.methods.hasSubmittedOrder = jest.fn();
mocks.baseMixin.methods.getSubmittedOrder = jest.fn();
mocks.baseMixin.methods.hasSubmittedOrder.mockReturnValue(true);
mocks.baseMixin.methods.getSubmittedOrder.mockReturnValue({
lineItems: {
supportingItems: [
{ partType: "RECALIBRATION", partNumber: "R1" },
{ partType: "DISPOSAL FEE", partNumber: "D1" },
{ partType: "MOBILE FEE", partNumber: "M1" },
{ partType: "REPAIR FEE", partNumber: "RF1" },
],
vaps: [{ partType: "FRONT WIPER", partNumber: "FW1" }],
},
payment: { isInsurance: true },
policy: { isItac: true, isNoComp: false },
});
// Call the function
analyticsMixin.methods.pushECommerceCartToDataLayer();
// Assertions
expect(mocks.baseMixin.methods.hasSubmittedOrder).toHaveBeenCalled();
expect(mocks.baseMixin.methods.getSubmittedOrder).toHaveBeenCalled();
expect(
mocks.baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts
).toHaveBeenCalled();
});
});
describe("pushCommissionJunctionGtmDataToDataLayer", () => {
const mocks = setupMocksForJsFiles();
it("should handle empty affiliateCookies", () => {
store.getters = {
applicationUser: {
affiliateCookies: [],
},
};
mocks.baseMixin.methods.hasSubmittedOrder = jest.fn();
mocks.baseMixin.methods.hasSubmittedOrder.mockReturnValue(false);
const result = analyticsMixin.methods.pushCommissionJunctionGtmDataToDataLayer();
expect(result).toBeUndefined();
});
test("Pushes populated data to data layer", () => {
mocks.baseMixin.methods.hasSubmittedOrder = jest.fn();
mocks.baseMixin.methods.hasSubmittedOrder.mockReturnValue(true);
mocks.baseMixin.methods.getSubmittedOrder = jest.fn();
mocks.baseMixin.methods.getSubmittedOrder.mockReturnValue({
vehicle: {
year: "2020",
make: "acura",
model: "mdx",
style: "4-door sedan",
carId: "dummyCarId",
category: "dummyCategory",
vin: "dummyVin",
},
serviceLocation: {
address: "add1",
address2: "add2",
city: "city",
state: "state",
zipCode: "11111",
zipCodeCtu: "11110",
appointmentType: "IN_SHOP",
isVehicleProtected: true,
provider: {
providerNumber: 2,
address: {
streetAddress: "add3",
city: "city2",
state: "state2",
zipCode: "22222",
zipCodeCtu: "22220",
},
},
techNotes: "",
},
customer: {
firstName: "first",
lastName: "last",
emailAddress: "builddigitaltest@safelite.com",
phoneNumber: "555-555-5555",
isSmsOptIn: false,
},
damage: {
isRepair: false,
numberOfChips: null,
glassToReplace: [{ glassName: "single", glassLocation: "windshield" }],
},
lineItems: {
glassParts: [parts.windshield],
supportingItems: [],
vaps: [parts.frontWipers],
promos: [
{
promoCode: "promoTEST",
kitPrice: 0,
sellingPrice: 0,
laborAmount: 0,
salesTax: 0,
},
{
promoCode: "promoTEST2",
kitPrice: 0,
sellingPrice: 0,
laborAmount: 0,
salesTax: 0,
},
],
},
payment: {
isInsurance: false,
insuranceCoverage: {
isVerified: null,
coverageStatus: null,
coverageVerificationType: null,
},
isPia: true,
piaType: "Afterpay",
inactivePromos: [],
},
schedule: {
date: "date",
startTime: "start",
endTime: "end",
jobMinMinutes: "30",
jobMaxMinutes: "45",
},
workOrderNumber: "01820-111111",
workOrderId: "222222222222",
referralSequenceNumber: "1111111",
});
store.getters = {
applicationUser: {
affiliateCookies: [
{
CookieName: "Cookie1",
CookieValue: "timestamp=2023-09-18/12:00:00&tagEvent=event1",
},
{
CookieName: "Cookie2",
CookieValue: "timestamp=2023-09-19/12:00:00&tagEvent=event2",
},
],
},
};
// Arrange
window.dataLayer = [];
// Act
analyticsMixin.methods.pushCommissionJunctionGtmDataToDataLayer();
const result = window.dataLayer[0];
// Assert
console.log(result);
const allFieldsPopulated = Object.keys(result).every(
(key) => result[key] === false || !!result[key]
);
expect(allFieldsPopulated).toBe(true);
});
});
});

View file

@ -145,6 +145,12 @@ const routes = [
await runExperiments(to.query.fmgPage);
//Affiliate Cookies
const affiliateCookies = getAffiliateCookies();
if (affiliateCookies != null && affiliateCookies.length > 0) {
store.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies);
}
setupAdvertiserTracking();
// Process funnel cookie.
updateOrCreateFunnelCookie();
@ -307,6 +313,17 @@ router.afterEach(async (to, from) => {
// Push current order status to Data Layer
analyticsMixin.methods.pushOrderToDataLayer();
if (to.query.fmgPage == fmgPageValues.CONFIRMATION) {
//Push Product Array to Data Layer
analyticsMixin.methods.pushProductArrayToDataLayer();
//Push Ecommerce Cart to Data Layer
analyticsMixin.methods.pushECommerceCartToDataLayer();
//Push Commission Junction Gtm Data To Data Layer
analyticsMixin.methods.pushCommissionJunctionGtmDataToDataLayer();
}
});
router.navigateWithoutSaving = (