Merge pull request #1702 from Safelite/feature/csr-1930
Feature/csr 1930
This commit is contained in:
commit
d81091addd
6 changed files with 251 additions and 0 deletions
|
|
@ -53,6 +53,7 @@ const storeMutations = {
|
|||
UPDATE_IS_PIA: "updateIsPia",
|
||||
UPDATE_PIA_TYPE: "updatePiaType",
|
||||
WORK_ORDER_NUMBER: "updateWorkOrderNumber",
|
||||
WORK_ORDER_ID: "updateWorkOrderId",
|
||||
Customer_Portal_Login_Token: "updateCustomerPortalLoginToken",
|
||||
LOCK_TOKEN: "updateLockToken",
|
||||
UPDATE_SETTLED_TENDER_AMOUNT: "updateSettledTenderAmount",
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ async function saveSessionHelper(
|
|||
crmCustomerId: savedSessionInfo.data.crmCustomerId?.toString(),
|
||||
eon: savedSessionInfo.data.eon,
|
||||
workOrderNumber: savedSessionInfo.data.workOrderNumber,
|
||||
workOrderId: savedSessionInfo.data.workOrderId,
|
||||
customerPortalLoginToken: savedSessionInfo.data.customerPortalLoginToken,
|
||||
lockToken: savedSessionInfo.data.lockToken,
|
||||
settledTenderAmount: savedSessionInfo.data.settledTenderAmount,
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ import cart from "@/fmg-components/cart/cart";
|
|||
|
||||
//Supporting files
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import analyticsMixin from "@/mixins/analytics-mixin";
|
||||
import store from "@/store";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
|
|
@ -134,6 +135,7 @@ export default {
|
|||
vm.setCmsContent(resultMap.cmsContent);
|
||||
vm.lineItems = lineItemsFromSubmittedOrder;
|
||||
vm.vaps = availableVaps;
|
||||
analyticsMixin.methods.pushSubmittedOrderToDataLayer();
|
||||
});
|
||||
},
|
||||
data() {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {
|
|||
GaEvents,
|
||||
ValueToLogTypes,
|
||||
} from "@/constants/analytics";
|
||||
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
||||
import store from "@/store";
|
||||
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
|
|
@ -119,6 +120,82 @@ export default {
|
|||
await this.logPageView(analyticsPageEvents.ENTRY);
|
||||
},
|
||||
|
||||
pushSubmittedOrderToDataLayer() {
|
||||
// check if submitted order exists; exit if not.
|
||||
const hasSubmittedOrder = store.getters.hasSubmittedOrder;
|
||||
|
||||
if (!hasSubmittedOrder) {
|
||||
return;
|
||||
}
|
||||
|
||||
const order = store.getters.submittedOrder;
|
||||
|
||||
// assemble data for payload
|
||||
// // reduce promocode array
|
||||
const promos = order.lineItems.promos ?? [];
|
||||
const promoCodes = promos.map((promo) => promo.promoCode);
|
||||
const promoString =
|
||||
promoCodes.length === 0 ? "" : promoCodes.reduce((prev, next) => `${prev},${next}`);
|
||||
|
||||
// // reduce glass array
|
||||
const glassToReplace = order.damage.glassToReplace ?? [];
|
||||
const glassToReplaceNames = glassToReplace.map(
|
||||
(glassPiece) => `${glassPiece.glassLocation}/${glassPiece.glassName}`
|
||||
);
|
||||
const glassString =
|
||||
glassToReplaceNames.length === 0
|
||||
? ""
|
||||
: glassToReplaceNames.reduce((prev, next) => `${prev},${next}`);
|
||||
|
||||
// // calculate subtotal
|
||||
const lineItems = order.lineItems;
|
||||
const combinedLineItems = [
|
||||
...(lineItems.glassParts ?? []),
|
||||
...(lineItems.supportingItems ?? []),
|
||||
...(lineItems.vaps ?? []),
|
||||
...(lineItems.promos ?? []),
|
||||
];
|
||||
const subtotal = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
|
||||
combinedLineItems,
|
||||
false
|
||||
);
|
||||
|
||||
// // get correct zip code
|
||||
const providerZip = order.serviceLocation.provider.address.zipCode;
|
||||
const serviceZip =
|
||||
order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|
||||
? order.serviceLocation.zipCode
|
||||
: providerZip;
|
||||
|
||||
// // calculate total
|
||||
const total = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts(
|
||||
combinedLineItems,
|
||||
true
|
||||
);
|
||||
|
||||
const payload = {
|
||||
serviceZipCode: serviceZip,
|
||||
damageType: order.damage.isRepair ? "repair" : "replace",
|
||||
accountType: order.payment.isInsurance ? "insurance" : "cash",
|
||||
promoCodes: promoString,
|
||||
vehicleYear: order.vehicle.year,
|
||||
vehicleMake: order.vehicle.make,
|
||||
vehicleModel: order.vehicle.model,
|
||||
vehicleStyle: order.vehicle.style,
|
||||
glassToReplace: glassString,
|
||||
workOrderId: order.workOrderId,
|
||||
providerCtu: order.serviceLocation.zipCodeCtu,
|
||||
orderNumber: order.workOrderNumber,
|
||||
priceTotal: total,
|
||||
priceSubTotal: subtotal,
|
||||
isRecalibrationOnOrder: store.getters.isRecalibrationOnSubmittedOrder,
|
||||
appointmentType: order.serviceLocation.appointmentType,
|
||||
};
|
||||
|
||||
// push to data layer.
|
||||
pushToDataLayerIfDefined(payload);
|
||||
},
|
||||
|
||||
pushExperimentsToDataLayer() {
|
||||
const experiments = store.getters.applicationUser.experiments;
|
||||
experiments?.forEach((exp) => {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,46 @@ import {
|
|||
getUserIdValue,
|
||||
} from "@/helpers/heritage-integration/cookie-helper";
|
||||
|
||||
const parts = {
|
||||
windshield: {
|
||||
name: "windshield",
|
||||
canSafeliteRecalibrate: true,
|
||||
childParts: [],
|
||||
color: "Green Tint",
|
||||
description:
|
||||
"solar, soundproofing, lane keep assist, lane departure warning system, w/adaptive cruise control",
|
||||
id: "db22fd44-10dd-456f-979b-ff88cf68cca6",
|
||||
partNumber: "FW04896GTYN",
|
||||
partType: "WINDSHIELD",
|
||||
recalibrationType: "STATIC",
|
||||
requiresCapabilityQuestions: false,
|
||||
requiresRecalibration: true,
|
||||
salesTax: 63.86,
|
||||
sellingPrice: 791.46,
|
||||
},
|
||||
frontWipers: {
|
||||
name: "front wipers",
|
||||
partNumber: "SBB16",
|
||||
description: "SAFELITE BEAM BLADE 16",
|
||||
partType: "FRONT WIPER",
|
||||
price: 32.64,
|
||||
},
|
||||
rearWipers: {
|
||||
name: "rear wipers",
|
||||
partNumber: "SBBR12A",
|
||||
description: "SAFELITE REAR BLADE 12A",
|
||||
partType: "REAR WIPER",
|
||||
price: 24.48,
|
||||
},
|
||||
rainDefense: {
|
||||
name: "rain defense",
|
||||
partNumber: "RAIN DEFENSE",
|
||||
description: null,
|
||||
partType: "RAIN DEFENSE",
|
||||
price: 35.5,
|
||||
},
|
||||
};
|
||||
|
||||
describe("analyticsMixin.js", () => {
|
||||
beforeEach(() => {
|
||||
removeAllTestCookies();
|
||||
|
|
@ -284,6 +324,130 @@ describe("analyticsMixin.js", () => {
|
|||
]);
|
||||
});
|
||||
|
||||
describe("pushSubmittedOrderToDataLayer", () => {
|
||||
beforeEach(() => {
|
||||
store.getters.hasSubmittedOrder = true;
|
||||
store.getters.submittedOrder = {
|
||||
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: "zip",
|
||||
zipCodeCtu: "zipCtu",
|
||||
appointmentType: "IN_SHOP",
|
||||
isVehicleProtected: true,
|
||||
provider: {
|
||||
providerNumber: 2,
|
||||
address: {
|
||||
streetAddress: "add3",
|
||||
city: "city2",
|
||||
state: "state2",
|
||||
zipCode: "zip2",
|
||||
zipCodeCtu: "zipCtu2",
|
||||
},
|
||||
},
|
||||
techNotes: "",
|
||||
},
|
||||
customer: {
|
||||
firstName: "first",
|
||||
lastName: "last",
|
||||
emailAddress: "builddigitaltest@safelite.com",
|
||||
phoneNumber: "555-555-5555",
|
||||
isSmsOptIn: false,
|
||||
},
|
||||
damage: {
|
||||
isRepair: false,
|
||||
numberOfChips: null,
|
||||
glassToReplace: [{ glassName: "single", location: "windshield" }],
|
||||
},
|
||||
lineItems: {
|
||||
glassParts: [parts.windshield],
|
||||
supportingItems: [],
|
||||
vaps: [parts.frontWipers],
|
||||
promos: [{ promoCode: "promoTEST" }, { promoCode: "promoTEST2" }],
|
||||
},
|
||||
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",
|
||||
};
|
||||
});
|
||||
|
||||
test("Pushes to data layer if nominal", () => {
|
||||
// Arrange
|
||||
const mockDataLayerFn = jest.fn();
|
||||
|
||||
window.dataLayer = {
|
||||
push: mockDataLayerFn,
|
||||
};
|
||||
|
||||
// Act
|
||||
analyticsMixin.methods.pushSubmittedOrderToDataLayer();
|
||||
|
||||
// Assert
|
||||
expect(mockDataLayerFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("Does not push to data layer if no submitted order available.", () => {
|
||||
// Arrange
|
||||
store.getters.hasSubmittedOrder = false;
|
||||
store.getters.submittedOrder = undefined;
|
||||
|
||||
const mockDataLayerFn = jest.fn();
|
||||
|
||||
window.dataLayer = {
|
||||
push: mockDataLayerFn,
|
||||
};
|
||||
|
||||
// Act
|
||||
analyticsMixin.methods.pushSubmittedOrderToDataLayer();
|
||||
|
||||
// Assert
|
||||
expect(mockDataLayerFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("Glass and Promo strings correctly formatted", () => {
|
||||
// Arrange
|
||||
window.dataLayer = [];
|
||||
|
||||
// Act
|
||||
analyticsMixin.methods.pushSubmittedOrderToDataLayer();
|
||||
|
||||
// Assert
|
||||
const glassString = window.dataLayer[0].glassToReplace;
|
||||
const promoString = window.dataLayer[0].promoCodes;
|
||||
|
||||
expect(glassString).toMatch(/(\w+\/\w+)?(,\w+\/\w+)*/);
|
||||
expect(promoString).toMatch(/(\w+)?(,\w+)*/);
|
||||
});
|
||||
});
|
||||
|
||||
test("Obj is not null after action prepended", () => {
|
||||
//Arrange
|
||||
const obj = { baseMethodName: "testMethodName", data: "testData" };
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ const getDefaultState = () => {
|
|||
referralCorrelationId: null,
|
||||
eon: null,
|
||||
workOrderNumber: null,
|
||||
workOrderId: null,
|
||||
customerPortalLoginToken: null,
|
||||
lockToken: null,
|
||||
settledTenderAmount: 0,
|
||||
|
|
@ -254,6 +255,9 @@ export const mutations = {
|
|||
updateWorkOrderNumber(state, workOrderNumber) {
|
||||
state.order.workOrderNumber = workOrderNumber;
|
||||
},
|
||||
updateWorkOrderId(state, workOrderId) {
|
||||
state.order.workOrderId = workOrderId;
|
||||
},
|
||||
updateCustomerPortalLoginToken(state, customerPortalLoginToken) {
|
||||
state.order.customerPortalLoginToken = customerPortalLoginToken;
|
||||
},
|
||||
|
|
@ -1027,6 +1031,7 @@ export const actions = {
|
|||
savedSessionId,
|
||||
crmCustomerId,
|
||||
workOrderNumber,
|
||||
workOrderId,
|
||||
customerPortalLoginToken,
|
||||
lockToken,
|
||||
settledTenderAmount,
|
||||
|
|
@ -1041,6 +1046,7 @@ export const actions = {
|
|||
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
|
||||
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
|
||||
context.commit(storeMutations.WORK_ORDER_NUMBER, workOrderNumber);
|
||||
context.commit(storeMutations.WORK_ORDER_ID, workOrderId);
|
||||
context.commit(storeMutations.LOCK_TOKEN, lockToken);
|
||||
context.commit(storeMutations.Customer_Portal_Login_Token, customerPortalLoginToken);
|
||||
context.commit(storeMutations.UPDATE_SETTLED_TENDER_AMOUNT, settledTenderAmount);
|
||||
|
|
|
|||
Loading…
Reference in a new issue