From e09248e98b9f634df2b534c8bee1c69fd0e2de8f Mon Sep 17 00:00:00 2001 From: Sneha Date: Tue, 10 Sep 2024 19:17:57 +0530 Subject: [PATCH 01/45] CSR-2201 --- src/constants/header-keys.js | 1 + src/global-methods.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/constants/header-keys.js b/src/constants/header-keys.js index 2cfbba367..13722fb6d 100644 --- a/src/constants/header-keys.js +++ b/src/constants/header-keys.js @@ -1,3 +1,4 @@ export const headerKeys = { EXPERIMENT: "X-Experiment-Data", + APPLICATION_NAME: "AppName", }; diff --git a/src/global-methods.js b/src/global-methods.js index c286ede9b..2d7e53262 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -60,6 +60,7 @@ export default { const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" }); const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), + [headerKeys.APPLICATION_NAME]: applicationConfig.APPLICATION_NAME, }; axios({ From eda4d7a149f55886a3b4d98df854c7ecce9ec97d Mon Sep 17 00:00:00 2001 From: Sneha Date: Fri, 13 Sep 2024 11:51:58 +0530 Subject: [PATCH 02/45] CSR-2201 extra headers --- src/constants/header-keys.js | 6 +++++- src/global-methods.js | 4 ++++ src/global-methods.spec.js | 1 + src/layouts/estimate/estimate.spec.js | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/constants/header-keys.js b/src/constants/header-keys.js index 13722fb6d..4c509f47b 100644 --- a/src/constants/header-keys.js +++ b/src/constants/header-keys.js @@ -1,4 +1,8 @@ export const headerKeys = { EXPERIMENT: "X-Experiment-Data", - APPLICATION_NAME: "AppName", + APPLICATION_NAME: "Application-Name", + REFERRAL_SEQUENCE_NUMBER: "referral-Sequence-Number", + SESSION_SEQUENCE_NUMBER: "session-Sequence-Number", + TRANSACTION_ID: "transaction-Id", + EON: "eon", }; diff --git a/src/global-methods.js b/src/global-methods.js index 2d7e53262..19d899887 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -61,6 +61,10 @@ export default { const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), [headerKeys.APPLICATION_NAME]: applicationConfig.APPLICATION_NAME, + [headerKeys.SESSION_SEQUENCE_NUMBER]: store.getters.applicationUser?.savedSessionId, + [headerKeys.REFERRAL_SEQUENCE_NUMBER]: store.getters.order?.referralSequenceNumber, + [headerKeys.TRANSACTION_ID]: crypto.randomUUID(), + [headerKeys.EON]: store.getters.order?.eon, }; axios({ diff --git a/src/global-methods.spec.js b/src/global-methods.spec.js index 93aafea81..e6c0e4858 100644 --- a/src/global-methods.spec.js +++ b/src/global-methods.spec.js @@ -13,6 +13,7 @@ global.$logger = { logError: jest.fn(), logCritical: jest.fn(), }; +global.crypto = { randomUUID: jest.fn() }; it("Global Methods - Call Http Client - Should Resolve Promise", () => { //Arrange diff --git a/src/layouts/estimate/estimate.spec.js b/src/layouts/estimate/estimate.spec.js index 7a66a197c..3487116f0 100644 --- a/src/layouts/estimate/estimate.spec.js +++ b/src/layouts/estimate/estimate.spec.js @@ -24,6 +24,7 @@ jest.mock("@/helpers/cms-content-helper", () => ({ fetchCmsContentForPage: jest.fn(), })); +global.crypto = { randomUUID: jest.fn() }; describe("estimate.vue", () => { test("Selected vin option is emitted upon selection.", async () => { //Arrange From e47f6e26df4ad2590be305b6f73f7c03d59f993b Mon Sep 17 00:00:00 2001 From: Sneha Date: Mon, 16 Sep 2024 12:48:28 +0530 Subject: [PATCH 03/45] Updating submittedOrder --- src/global-methods.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/global-methods.js b/src/global-methods.js index 19d899887..6afeef53d 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -1,5 +1,6 @@ import axios from "axios"; import analyticsMixIn from "@/mixins/analytics-mixin.js"; +import baseMixin from "@/mixins/base-mixin.js"; import router from "@/router"; import store from "@/store"; @@ -57,14 +58,17 @@ export default { }) { return new Promise((resolve, reject) => { const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; + const submittedOrder = baseMixin.methods.getSubmittedOrder(); + const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder(); + const order = hasSubmittedOrder ? submittedOrder : store.getters.order; const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" }); const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), [headerKeys.APPLICATION_NAME]: applicationConfig.APPLICATION_NAME, [headerKeys.SESSION_SEQUENCE_NUMBER]: store.getters.applicationUser?.savedSessionId, - [headerKeys.REFERRAL_SEQUENCE_NUMBER]: store.getters.order?.referralSequenceNumber, + [headerKeys.REFERRAL_SEQUENCE_NUMBER]: order?.referralSequenceNumber, [headerKeys.TRANSACTION_ID]: crypto.randomUUID(), - [headerKeys.EON]: store.getters.order?.eon, + [headerKeys.EON]: order?.eon, }; axios({ From d1b4d4e1f130f2dffe95d3164212fe9ca6a5c6b7 Mon Sep 17 00:00:00 2001 From: Sneha Date: Mon, 16 Sep 2024 18:11:14 +0530 Subject: [PATCH 04/45] Update header-keys.js --- src/constants/header-keys.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/constants/header-keys.js b/src/constants/header-keys.js index 4c509f47b..03b88b5cb 100644 --- a/src/constants/header-keys.js +++ b/src/constants/header-keys.js @@ -1,8 +1,8 @@ export const headerKeys = { EXPERIMENT: "X-Experiment-Data", - APPLICATION_NAME: "Application-Name", - REFERRAL_SEQUENCE_NUMBER: "referral-Sequence-Number", - SESSION_SEQUENCE_NUMBER: "session-Sequence-Number", - TRANSACTION_ID: "transaction-Id", - EON: "eon", + APPLICATION_NAME: "X-Application-Name", + REFERRAL_SEQUENCE_NUMBER: "X-Referral-Sequence-Number", + SESSION_SEQUENCE_NUMBER: "X-Session-Sequence-Number", + TRANSACTION_ID: "X-Transaction-Id", + EON: "X-Eon", }; From eeea9c3c7a3b52fc96a1c93bfbe9fe5327a4374e Mon Sep 17 00:00:00 2001 From: Sneha Date: Mon, 16 Sep 2024 18:17:00 +0530 Subject: [PATCH 05/45] Update EON --- src/constants/header-keys.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/header-keys.js b/src/constants/header-keys.js index 03b88b5cb..7caaef65c 100644 --- a/src/constants/header-keys.js +++ b/src/constants/header-keys.js @@ -4,5 +4,5 @@ export const headerKeys = { REFERRAL_SEQUENCE_NUMBER: "X-Referral-Sequence-Number", SESSION_SEQUENCE_NUMBER: "X-Session-Sequence-Number", TRANSACTION_ID: "X-Transaction-Id", - EON: "X-Eon", + EON: "X-EON", }; From 534337b48b7c486b80e030358c0a49d83e2067ec Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 18 Sep 2024 10:23:15 -0400 Subject: [PATCH 06/45] CSR-1804 | Utilize billToAccountNumber endpoint Only fires when zip changes on service-location --- src/constants/endpoints.js | 4 ++ src/constants/store-actions.js | 1 + .../service-location-helper.js | 22 +++++++---- .../mobile-location-modal-questions.vue | 8 +++- .../service-location/service-location.vue | 13 +++++++ .../service-zip-modal-question.vue | 8 +++- src/store/index.js | 39 +++++++++++++++++++ 7 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 0c75258e9..ed880269c 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -172,6 +172,10 @@ const endpoints = { url: "/account/api/v1/account/insurance-companies", method: "GET", }, + GetBillToAccountNumber: { + url: "/account/api/v1/account/bill-to-account-number", + method: "GET", + }, }; export { endpoints }; diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 069079d35..4cd03771e 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -53,6 +53,7 @@ const storeActions = { VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA: "validateOrderPromoAndSaveServerData", REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA: "revalidateOrderPromosAndSaveServerData", GET_INSURANCE_COMPANY_LIST: "getInsuranceCompanyList", + GET_BILL_TO_ACCOUNT_NUMBER: "getBillToAccountNumber", // DEPENDENCY MUTATIONS RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies", diff --git a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js index e92349ddf..1e7b6bdb3 100644 --- a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js +++ b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js @@ -3,7 +3,7 @@ import baseMixin from "@/mixins/base-mixin.js"; export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) { if (!serviceZipCode) { - return Promise.resolve(null); + return null; } const zipCodeData = await baseMixin.methods.getZipCodeData(serviceZipCode, pageNameToLog); @@ -36,12 +36,12 @@ export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) { false ); - return Promise.resolve(pricingResults[0]); + return pricingResults[0]; } export async function getServiceabilityDetails(serviceZipCode, lineItems, pageNameToLog) { // Get the Mobile Fee Part - const serviceabilityDetails = await baseMixin.methods.dispatchStoreActionWithLogging( + return await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_SERVICEABILITY_DETAILS, { serviceZipCode: serviceZipCode, @@ -50,20 +50,26 @@ export async function getServiceabilityDetails(serviceZipCode, lineItems, pageNa pageNameToLog, false ); +} - return Promise.resolve(serviceabilityDetails); +export async function getBillToAccountNumber(providerNumber) { + // Get the BillTo Account Number + return await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.GET_BILL_TO_ACCOUNT_NUMBER, + { providerNumber: providerNumber }, + "service-location", + false + ); } export async function getShopProviderData(serviceZipCode) { - const shopProviderData = await baseMixin.methods.dispatchStoreActionWithLogging( + return await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_PROVIDERS, { serviceZipCode: serviceZipCode, }, "service-location" ); - - return Promise.resolve(shopProviderData); } export async function getAvailabilityRating( @@ -92,5 +98,5 @@ export async function getAvailabilityRating( const shopStatus = isGoodAvailability ? "high" : "low"; - return Promise.resolve(shopStatus); + return shopStatus; } diff --git a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue index 4bdc00cb3..40fc698ac 100644 --- a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue +++ b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue @@ -83,6 +83,7 @@ import { deepClone } from "@/helpers/object-helper"; import { getPricedMobileFeePart, getServiceabilityDetails, + getBillToAccountNumber, } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper"; // Validation @@ -91,7 +92,7 @@ import { v4 as uuidv4 } from "uuid"; export default { name: "mobile-location-modal-questions", - emits: ["update:modelValue", "updated-mobile-fee-part", "updated-contains-military-base"], + emits: ["update:modelValue", "updated-mobile-fee-part", "updated-contains-military-base", "updated-bill-to-account-number"], data() { return { internalModel: deepClone(this.modelValue), @@ -266,11 +267,16 @@ export default { "service-location" ); + const billToAccountNumber = await getBillToAccountNumber( + this.internalModel.zipCodeCtu + ); + // update content related to service zip code this.$emit("updated-mobile-fee-part", mobileFeePart); this.$emit("updated-serviceability", serviceabilityDetails.data); this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase); this.$emit("updated-mobile-ctu", zipCodeData.zipCodeCtu); + this.$emit("updated-bill-to-account-number", billToAccountNumber); // update the page level model this.$emit("update:modelValue", this.internalModel); diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index f9a2ec240..badd8a204 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -19,6 +19,7 @@ @updated-mobile-fee-part="setMobileFeePart" @updated-serviceability="setServiceabilityDetails" @updated-contains-military-base="setContainsMilitaryBase" + @updated-bill-to-account-number="setBillToAccountNumber" linkWidgetName="ServiceZipLinkWidget" modalWidgetName="ServiceZipModalWidget" /> @@ -191,6 +192,7 @@ export default { mobileFeePart: null, zipContainsMilitaryBase: false, zipCodeCtu: null, + billToAccountNumber: null, shopProviderData: null, navigatingForward: false, }; @@ -437,6 +439,9 @@ export default { this.zipContainsMilitaryBase = val; } }, + setBillToAccountNumber(val) { + this.billToAccountNumber = val; + }, setCtuForMobile(val) { this.zipCodeCtu = val; }, @@ -601,6 +606,14 @@ export default { }, false ); + console.log(this.billToAccountNumber); + if (this.billToAccountNumber) { + this.dispatchStoreAction( + this.storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER, + this.billToAccountNumber, + false + ); + } this.updateAndSaveSupportingItems(); this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route); diff --git a/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue b/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue index 841dfe153..5272ab52e 100644 --- a/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue +++ b/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue @@ -46,11 +46,12 @@ import alert from "@/ux-components/alert/alert"; import { getPricedMobileFeePart, getServiceabilityDetails, + getBillToAccountNumber } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper"; export default { name: "service-zip-modal-question", - emits: ["update:modelValue", "updated-mobile-fee-part", "updated-contains-military-base"], + emits: ["update:modelValue", "updated-mobile-fee-part", "updated-contains-military-base", "updated-bill-to-account-number"], data() { return { internalModel: this.copyModel(this.modelValue), @@ -165,10 +166,15 @@ export default { "service-location" ); + const billToAccountNumber = await getBillToAccountNumber( + this.internalModel.zipCodeCtu + ); + // update content related to service zip code this.$emit("updated-mobile-fee-part", mobileFeePart); this.$emit("updated-serviceability", serviceabilityDetails.data); this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase); + this.$emit("updated-bill-to-account-number", billToAccountNumber); // update the page level model this.$emit("update:modelValue", this.internalModel); diff --git a/src/store/index.js b/src/store/index.js index 130f1e7c1..6cd534730 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1881,6 +1881,7 @@ export const actions = { }, isInsurance: order.payment.isInsurance, parentAccountNumber: order.payment.parentAccountNumber, + billToAccountNumber: order.payment.billToAccountNumber, inactivePromos: order.payment.inactivePromos, isCreditCard: order.payment.piaType == paymentMethods.CREDIT_CARD ? true : false, @@ -2669,6 +2670,10 @@ export const actions = { return revalidateResponse?.data; }, + /////////////////////////// + // Account Service Calls // + /////////////////////////// + // List all insurance companies async getInsuranceCompanyList(context, { pageNameToLog }) { const insuranceCompanyList = await globalMethods.callHttpClient({ @@ -2691,6 +2696,40 @@ export const actions = { return 0; }); }, + // Get BillToAccountNumber + async getBillToAccountNumber( + context, + { + payload: { + parentAccountNumber = context.getters.order.payment.parentAccountNumber, + providerNumber = context.getters.order.serviceLocation.zipCodeCtu, + isItac = context.getters.order.policy.isItac, + }, + pageNameToLog, + } + ) { + // Cash orders default to 87291 - update if/when more detailed + // billToAccountNumbers are needed for cash + if (parentAccountNumber == applicationConfig.CASH_PARENT_ACCOUNT_NUMBER) { + return applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER; + } + const queryString = + `ParentAccountNumber=${parentAccountNumber}` + + `&ProviderNumber=${providerNumber}` + + `&IsItac=${isItac}`; + + const billToAccountNumberResponse = await globalMethods.callHttpClient({ + method: endpoints.GetBillToAccountNumber.method, + endpoint: `${endpoints.GetBillToAccountNumber.url}?${queryString}`, + logApiCall: true, + pageNameToLog: pageNameToLog, + }); + + return billToAccountNumberResponse.data.toString(); + }, + ////////////////////////////////// + // END OF Account Service Calls // + ////////////////////////////////// // Misc order actions saveSchedule(context, scheduleInfo) { From 51f93741048a7ede8bb04d2d6bbeea67baca1191 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 18 Sep 2024 11:36:47 -0400 Subject: [PATCH 07/45] CSR-1804 | Unit test and formatting changes --- src/global-methods.js | 5 ++++- .../mobile-location-modal-questions.spec.js | 4 ++++ .../mobile-location-modal-questions.vue | 7 ++++++- .../service-zip-modal-question.spec.js | 4 ++++ .../service-zip-modal-question.vue | 9 +++++++-- src/store/index.js | 5 +++-- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/global-methods.js b/src/global-methods.js index c286ede9b..ba534eeab 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -56,7 +56,10 @@ export default { additionalSuccessEventDataHandler, }) { return new Promise((resolve, reject) => { - const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; + let cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; + if (endpoint.includes("/order/")) { + cfDistroUrl = "https://localhost:44346"; + } const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" }); const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), diff --git a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.spec.js b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.spec.js index 56833dbaa..863a04c82 100644 --- a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.spec.js +++ b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.spec.js @@ -2,6 +2,7 @@ import mobileLocationModalQuestions from "./mobile-location-modal-questions"; import { mount, shallowMount } from "@vue/test-utils"; import { storeActions } from "@/constants/store-actions"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { getBillToAccountNumber } from "../helpers/service-location-helper/service-location-helper"; const linkWidgetName = "linkWidgetName"; const modalWidgetName = "modalWidgetName"; @@ -125,6 +126,9 @@ jest.mock( getServiceabilityDetails: jest.fn((mockServiceZipCode) => { return mockGetServiceabilityDetails(mockServiceZipCode); }), + getBillToAccountNumber: jest.fn(() => { + return "87291"; + }), }) ); diff --git a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue index 40fc698ac..89e095279 100644 --- a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue +++ b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue @@ -92,7 +92,12 @@ import { v4 as uuidv4 } from "uuid"; export default { name: "mobile-location-modal-questions", - emits: ["update:modelValue", "updated-mobile-fee-part", "updated-contains-military-base", "updated-bill-to-account-number"], + emits: [ + "update:modelValue", + "updated-mobile-fee-part", + "updated-contains-military-base", + "updated-bill-to-account-number", + ], data() { return { internalModel: deepClone(this.modelValue), diff --git a/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.spec.js b/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.spec.js index 7c09836fe..ed8a811ed 100644 --- a/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.spec.js +++ b/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.spec.js @@ -1,5 +1,6 @@ import { mount, shallowMount } from "@vue/test-utils"; import serviceZipModalQuestion from "./service-zip-modal-question"; +import { getBillToAccountNumber } from "../helpers/service-location-helper/service-location-helper"; jest.mock("@/digital-components/textbox-question/textbox-question", () => ({ getCmsContent: jest.fn((widgetName, cmsFieldName) => { @@ -51,6 +52,9 @@ jest.mock( getServiceabilityDetails: jest.fn((mockServiceZipCode) => { return mockGetServiceabilityDetails(mockServiceZipCode); }), + getBillToAccountNumber: jest.fn((mockServiceZipCodeCtu) => { + return "87291"; + }), }) ); diff --git a/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue b/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue index 5272ab52e..c0231ea80 100644 --- a/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue +++ b/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue @@ -46,12 +46,17 @@ import alert from "@/ux-components/alert/alert"; import { getPricedMobileFeePart, getServiceabilityDetails, - getBillToAccountNumber + getBillToAccountNumber, } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper"; export default { name: "service-zip-modal-question", - emits: ["update:modelValue", "updated-mobile-fee-part", "updated-contains-military-base", "updated-bill-to-account-number"], + emits: [ + "update:modelValue", + "updated-mobile-fee-part", + "updated-contains-military-base", + "updated-bill-to-account-number", + ], data() { return { internalModel: this.copyModel(this.modelValue), diff --git a/src/store/index.js b/src/store/index.js index 6cd534730..6faeab921 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2422,8 +2422,9 @@ export const actions = { })); const order = context.getters.order; - - var providerNumber = order.serviceLocation?.provider?.providerNumber ?? order.serviceLocation?.zipCodeCtu; + + var providerNumber = + order.serviceLocation?.provider?.providerNumber ?? order.serviceLocation?.zipCodeCtu; if (providerNumber.startsWith("00") && providerNumber.length > 5) { providerNumber = providerNumber.substring(1); } From 871ca0d5d72f25ff98639ed132c1c709f2e5bd94 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Wed, 18 Sep 2024 14:13:52 -0400 Subject: [PATCH 08/45] CSR-2166: temporary test for DEV ONLY; will be reverted 9/18/24 --- src/layouts/part-questions/part-questions.vue | 5 +++++ src/layouts/quote/quote.vue | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index f49f5876c..600b9947c 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -55,6 +55,11 @@ export default { next((vm) => { vm.setCmsContent(resultMap.cmsContent); if (store.getters.externalParameterState?.isExternalParameter) { + + // check experiments + const testExperiments = store.getters.externalParameterQuote?.isInsurance; + console.warn("TEMP TEST AJC /// PART-QUESTIONS PAGE /// experiments: ", testExperiments) + baseMixin.methods.ResetExternalParamsAndHideModal(); } }); diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 660681da1..a665c38bb 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -294,6 +294,11 @@ export default { } if (store.getters.externalParameterState?.isExternalParameter) { + + // check experiments + const testExperiments = store.getters.externalParameterQuote?.isInsurance; + console.warn("TEMP TEST AJC /// QUOTE PAGE /// experiments: ", testExperiments) + if (store.getters.externalParameterQuote.isInsurance == true) { vm.isInsuranceSelected = true; vm.servicePackage = store.getters.externalParameterQuote.servicePackage; From 2305a57f0a7ff26a16e44052474fd3bc155b1085 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Wed, 18 Sep 2024 15:29:05 -0400 Subject: [PATCH 09/45] CSR-2166: revert temporary test for DEV ONLY --- src/layouts/part-questions/part-questions.vue | 5 ----- src/layouts/quote/quote.vue | 5 ----- 2 files changed, 10 deletions(-) diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index 600b9947c..f49f5876c 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -55,11 +55,6 @@ export default { next((vm) => { vm.setCmsContent(resultMap.cmsContent); if (store.getters.externalParameterState?.isExternalParameter) { - - // check experiments - const testExperiments = store.getters.externalParameterQuote?.isInsurance; - console.warn("TEMP TEST AJC /// PART-QUESTIONS PAGE /// experiments: ", testExperiments) - baseMixin.methods.ResetExternalParamsAndHideModal(); } }); diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index a665c38bb..660681da1 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -294,11 +294,6 @@ export default { } if (store.getters.externalParameterState?.isExternalParameter) { - - // check experiments - const testExperiments = store.getters.externalParameterQuote?.isInsurance; - console.warn("TEMP TEST AJC /// QUOTE PAGE /// experiments: ", testExperiments) - if (store.getters.externalParameterQuote.isInsurance == true) { vm.isInsuranceSelected = true; vm.servicePackage = store.getters.externalParameterQuote.servicePackage; From e538f4d8c2ee8e5382db458597f39c2722c58394 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Wed, 18 Sep 2024 15:32:07 -0400 Subject: [PATCH 10/45] CSR-2166: add experiments as an externalParameter in store and capture in router --- src/constants/query-strings.js | 1 + src/constants/store-mutations.js | 1 + src/router/index.js | 7 +++++++ src/store/index.js | 6 ++++++ 4 files changed, 15 insertions(+) diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 9fb379836..3cdfd655f 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -44,6 +44,7 @@ const queryStrings = { CJUNCTION: "cjunction", ORGANIC: "organic", ORGANIC_SOCIAL: "organic_social", + EXPERIMENTS: "experiments", }; export { queryStrings }; diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index 494be36e3..a2e630454 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -103,6 +103,7 @@ const storeMutations = { UPDATE_EXTERNAL_PARAMETER_IS_INSURANCE: "updateExternalParameterIsInsurance", UPDATE_EXTERNAL_PARAMETER_VIN_SELECTION: "updateExternalParameterVinSelection", UPDATE_EXTERNAL_PARAMETER_SERVICE_PACKAGE: "updateExternalParameterServicePackage", + UPDATE_EXTERNAL_PARAMETER_EXPERIMENTS: "updateExternalParameterExperiments", //RESET EXTERNAL_PARAMETER MUTATIONS RESET_EXTERNAL_PARAMETER_VEHICLE_STATE: "resetExternalParameterVehicleState", diff --git a/src/router/index.js b/src/router/index.js index 4549f9e7c..c58151002 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -615,6 +615,7 @@ function updateExternalParameterState() { const externalParameterVinSelection = getQuerystringParameter(queryStrings.VIN_SELECTION); const externalParameterServicePackage = getQuerystringParameter(queryStrings.SERVICE_PACKAGE); const externalParameterNumberOfChips = getQuerystringParameter(queryStrings.NUMBER_OF_CHIPS); + const externalParameterExperiments = getQuerystringParameter(queryStrings.EXPERIMENTS); if ( externalParameterYear && externalParameterMake && @@ -664,6 +665,12 @@ function updateExternalParameterState() { externalParameterVinSelection ); } + if (externalParameterExperiments) { + store.commit( + storeMutations.UPDATE_EXTERNAL_PARAMETER_EXPERIMENTS, + externalParameterExperiments + ); + } } export default router; diff --git a/src/store/index.js b/src/store/index.js index 6faeab921..587f71df8 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -472,6 +472,10 @@ export const mutations = { externalParameterState.quote.servicePackage = servicePackage; saveExternalParameterState(externalParameterState); }, + updateExternalParameterExperiments(state, experiments) { + externalParameterState.quote.experiments = experiments; + saveExternalParameterState(externalParameterState); + }, //RESET ExternalParameter MUTATIONS resetExternalParameterVehicleState(state) { externalParameterState.vehicle.year = null; @@ -500,6 +504,7 @@ export const mutations = { resetExternalParameterQuoteState(state) { externalParameterState.quote.isInsurance = null; externalParameterState.quote.servicePackage = null; + externalParameterState.quote.experiments = null; saveExternalParameterState(externalParameterState); }, resetIsExternalParameter(state) { @@ -3402,6 +3407,7 @@ function createExternalParameterDefaultState() { quote: { isInsurance: null, servicePackage: null, + experiments: null, }, }; // set to session storage From 2fb672604477c3c54a772a97b8ef9d6e098fee3e Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Thu, 19 Sep 2024 16:11:08 +0530 Subject: [PATCH 11/45] CSR-1629 CJ Pixel tracking and product array for CJ conversion tag and eCommerceCart for subTotal --- src/mixins/analytics-mixin.js | 249 ++++++++++++++++++++++++++++++++++ src/router/index.js | 17 +++ 2 files changed, 266 insertions(+) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 9ce6874ae..dc4da7e1b 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -381,6 +381,234 @@ 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); + 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) @@ -493,3 +721,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; +} diff --git a/src/router/index.js b/src/router/index.js index 23b61282c..cbd2d2eab 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -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 = ( From 315acd49a7e4a6cd3659d379769a5b2228baaaab Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Thu, 19 Sep 2024 19:03:59 +0530 Subject: [PATCH 12/45] CSR-1629 unit test cases --- src/mixins/analytics-mixin.js | 55 ++++---- src/mixins/analytics-mixin.spec.js | 196 +++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+), 27 deletions(-) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index dc4da7e1b..615e5ecf6 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -546,7 +546,7 @@ export default { const affiliateCookies = store.getters.applicationUser.affiliateCookies; var cookieArray = []; affiliateCookies.forEach((item) => { - let cookieObject = convertCookieStringToObject(item); + let cookieObject = convertCookieStringToObject(item.CookieValue); cookieArray.push(cookieObject); }); const sortedCookies = cookieArray.sort( @@ -569,33 +569,34 @@ export default { 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); + 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({ diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js index e56840c61..6266b97a1 100644 --- a/src/mixins/analytics-mixin.spec.js +++ b/src/mixins/analytics-mixin.spec.js @@ -1,4 +1,6 @@ import analyticsMixin from "@/mixins/analytics-mixin"; +import baseMixin from "@/mixins/base-mixin"; +import { shallowMount } from "@vue/test-utils"; import { setupMocksForJsFiles, setupCookies, @@ -851,4 +853,198 @@ describe("analyticsMixin.js", () => { expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled(); }); }); + describe("push product array and ecommerce cart to data layer", () => { + let wrapper; + + beforeEach(() => { + wrapper = shallowMount(analyticsMixin); + }); + + it("should push product array to data layer correctly", () => { + // Mock the methods + baseMixin.methods.hasSubmittedOrder = jest.fn(); + baseMixin.methods.getSubmittedOrder = jest.fn(); + baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts = jest.fn(); + baseMixin.methods.hasSubmittedOrder.mockReturnValue(true); + 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" }], + }, + }); + baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts.mockReturnValue(100); + + // Call the function + wrapper.vm.pushProductArrayToDataLayer(); + + // Assertions + expect(baseMixin.methods.hasSubmittedOrder).toHaveBeenCalled(); + expect(baseMixin.methods.getSubmittedOrder).toHaveBeenCalled(); + expect(baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts).toHaveBeenCalled(); + }); + it("should push eCommerce cart to data layer correctly", () => { + // Mock the methods + (baseMixin.methods.hasSubmittedOrder = jest.fn()), + (baseMixin.methods.getSubmittedOrder = jest.fn()), + baseMixin.methods.hasSubmittedOrder.mockReturnValue(true); + 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 + wrapper.vm.pushECommerceCartToDataLayer(); + + // Assertions + expect(baseMixin.methods.hasSubmittedOrder).toHaveBeenCalled(); + expect(baseMixin.methods.getSubmittedOrder).toHaveBeenCalled(); + expect(baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts).toHaveBeenCalled(); + }); + }); + + describe("pushCommissionJunctionGtmDataToDataLayer", () => { + it("should handle empty affiliateCookies", () => { + store.getters = { + applicationUser: { + affiliateCookies: [], + }, + }; + + baseMixin.methods.hasSubmittedOrder = jest.fn(); + baseMixin.methods.hasSubmittedOrder.mockReturnValue(false); + const result = analyticsMixin.methods.pushCommissionJunctionGtmDataToDataLayer(); + expect(result).toBeUndefined(); + }); + + test("Pushes populated data to data layer", () => { + baseMixin.methods.hasSubmittedOrder = jest.fn(); + baseMixin.methods.hasSubmittedOrder.mockReturnValue(true); + baseMixin.methods.getSubmittedOrder = jest.fn(); + 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); + }); + }); }); From 0ca54edddf80b22990a89c96cb2380b2dcd95111 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Thu, 19 Sep 2024 10:01:01 -0400 Subject: [PATCH 13/45] CSR-2166: updates to external parameter naming --- src/constants/store-mutations.js | 2 +- src/router/index.js | 8 ++++---- src/store/index.js | 11 +++++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index a2e630454..c03d51432 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -103,7 +103,7 @@ const storeMutations = { UPDATE_EXTERNAL_PARAMETER_IS_INSURANCE: "updateExternalParameterIsInsurance", UPDATE_EXTERNAL_PARAMETER_VIN_SELECTION: "updateExternalParameterVinSelection", UPDATE_EXTERNAL_PARAMETER_SERVICE_PACKAGE: "updateExternalParameterServicePackage", - UPDATE_EXTERNAL_PARAMETER_EXPERIMENTS: "updateExternalParameterExperiments", + UPDATE_EXTERNAL_PARAMETER_SOURCE: "updateExternalParameterSource", //RESET EXTERNAL_PARAMETER MUTATIONS RESET_EXTERNAL_PARAMETER_VEHICLE_STATE: "resetExternalParameterVehicleState", diff --git a/src/router/index.js b/src/router/index.js index c58151002..83a7b0148 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -615,7 +615,7 @@ function updateExternalParameterState() { const externalParameterVinSelection = getQuerystringParameter(queryStrings.VIN_SELECTION); const externalParameterServicePackage = getQuerystringParameter(queryStrings.SERVICE_PACKAGE); const externalParameterNumberOfChips = getQuerystringParameter(queryStrings.NUMBER_OF_CHIPS); - const externalParameterExperiments = getQuerystringParameter(queryStrings.EXPERIMENTS); + const externalParameterSource = getQuerystringParameter(queryStrings.EXPERIMENTS); if ( externalParameterYear && externalParameterMake && @@ -665,10 +665,10 @@ function updateExternalParameterState() { externalParameterVinSelection ); } - if (externalParameterExperiments) { + if (externalParameterSource) { store.commit( - storeMutations.UPDATE_EXTERNAL_PARAMETER_EXPERIMENTS, - externalParameterExperiments + storeMutations.UPDATE_EXTERNAL_PARAMETER_SOURCE, + externalParameterSource ); } } diff --git a/src/store/index.js b/src/store/index.js index 587f71df8..6ed37e445 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -472,8 +472,8 @@ export const mutations = { externalParameterState.quote.servicePackage = servicePackage; saveExternalParameterState(externalParameterState); }, - updateExternalParameterExperiments(state, experiments) { - externalParameterState.quote.experiments = experiments; + updateExternalParameterSource(state, source) { + externalParameterState.source = source; saveExternalParameterState(externalParameterState); }, //RESET ExternalParameter MUTATIONS @@ -504,7 +504,10 @@ export const mutations = { resetExternalParameterQuoteState(state) { externalParameterState.quote.isInsurance = null; externalParameterState.quote.servicePackage = null; - externalParameterState.quote.experiments = null; + saveExternalParameterState(externalParameterState); + }, + resetExternalParameterSourceState(state) { + externalParameterState.source = null; saveExternalParameterState(externalParameterState); }, resetIsExternalParameter(state) { @@ -3407,8 +3410,8 @@ function createExternalParameterDefaultState() { quote: { isInsurance: null, servicePackage: null, - experiments: null, }, + source: null, }; // set to session storage saveExternalParameterState(externalParameterDefaultState); From 7f58966fa5416f3d48de6a5bf31586b314394dca Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Thu, 19 Sep 2024 19:31:31 +0530 Subject: [PATCH 14/45] CSR-1629 unit test cases --- src/mixins/analytics-mixin.spec.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js index 6266b97a1..9ad38f86d 100644 --- a/src/mixins/analytics-mixin.spec.js +++ b/src/mixins/analytics-mixin.spec.js @@ -1,6 +1,5 @@ import analyticsMixin from "@/mixins/analytics-mixin"; import baseMixin from "@/mixins/base-mixin"; -import { shallowMount } from "@vue/test-utils"; import { setupMocksForJsFiles, setupCookies, @@ -854,12 +853,6 @@ describe("analyticsMixin.js", () => { }); }); describe("push product array and ecommerce cart to data layer", () => { - let wrapper; - - beforeEach(() => { - wrapper = shallowMount(analyticsMixin); - }); - it("should push product array to data layer correctly", () => { // Mock the methods baseMixin.methods.hasSubmittedOrder = jest.fn(); @@ -877,7 +870,7 @@ describe("analyticsMixin.js", () => { baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts.mockReturnValue(100); // Call the function - wrapper.vm.pushProductArrayToDataLayer(); + analyticsMixin.methods.pushProductArrayToDataLayer(); // Assertions expect(baseMixin.methods.hasSubmittedOrder).toHaveBeenCalled(); @@ -904,7 +897,7 @@ describe("analyticsMixin.js", () => { }); // Call the function - wrapper.vm.pushECommerceCartToDataLayer(); + analyticsMixin.methods.pushECommerceCartToDataLayer(); // Assertions expect(baseMixin.methods.hasSubmittedOrder).toHaveBeenCalled(); From 933434adff32957cd82172714291c5d7c764d6c7 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Thu, 19 Sep 2024 20:43:12 +0530 Subject: [PATCH 15/45] CSR-1629 unit test case fixes --- src/mixins/analytics-mixin.spec.js | 51 ++++++++++++++++-------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js index 9ad38f86d..8f63854a0 100644 --- a/src/mixins/analytics-mixin.spec.js +++ b/src/mixins/analytics-mixin.spec.js @@ -1,5 +1,4 @@ import analyticsMixin from "@/mixins/analytics-mixin"; -import baseMixin from "@/mixins/base-mixin"; import { setupMocksForJsFiles, setupCookies, @@ -853,13 +852,14 @@ describe("analyticsMixin.js", () => { }); }); 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 - baseMixin.methods.hasSubmittedOrder = jest.fn(); - baseMixin.methods.getSubmittedOrder = jest.fn(); - baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts = jest.fn(); - baseMixin.methods.hasSubmittedOrder.mockReturnValue(true); - baseMixin.methods.getSubmittedOrder.mockReturnValue({ + 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" }], @@ -867,22 +867,24 @@ describe("analyticsMixin.js", () => { promos: [{ partNumber: "DISCOUNT", partType: "promo", promoCode: "PROMO4" }], }, }); - baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts.mockReturnValue(100); + mocks.baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts.mockReturnValue(100); // Call the function analyticsMixin.methods.pushProductArrayToDataLayer(); // Assertions - expect(baseMixin.methods.hasSubmittedOrder).toHaveBeenCalled(); - expect(baseMixin.methods.getSubmittedOrder).toHaveBeenCalled(); - expect(baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts).toHaveBeenCalled(); + 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 - (baseMixin.methods.hasSubmittedOrder = jest.fn()), - (baseMixin.methods.getSubmittedOrder = jest.fn()), - baseMixin.methods.hasSubmittedOrder.mockReturnValue(true); - baseMixin.methods.getSubmittedOrder.mockReturnValue({ + 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" }, @@ -900,13 +902,16 @@ describe("analyticsMixin.js", () => { analyticsMixin.methods.pushECommerceCartToDataLayer(); // Assertions - expect(baseMixin.methods.hasSubmittedOrder).toHaveBeenCalled(); - expect(baseMixin.methods.getSubmittedOrder).toHaveBeenCalled(); - expect(baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts).toHaveBeenCalled(); + 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: { @@ -914,17 +919,17 @@ describe("analyticsMixin.js", () => { }, }; - baseMixin.methods.hasSubmittedOrder = jest.fn(); - baseMixin.methods.hasSubmittedOrder.mockReturnValue(false); + 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", () => { - baseMixin.methods.hasSubmittedOrder = jest.fn(); - baseMixin.methods.hasSubmittedOrder.mockReturnValue(true); - baseMixin.methods.getSubmittedOrder = jest.fn(); - baseMixin.methods.getSubmittedOrder.mockReturnValue({ + 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", From 4ab4438344f4bea430d7cb11e0705369dbd37470 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Thu, 19 Sep 2024 18:02:27 -0400 Subject: [PATCH 16/45] CSR-2166: adding a few missed state methods --- src/constants/store-mutations.js | 1 + src/store/index.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index c03d51432..02b05bd28 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -111,6 +111,7 @@ const storeMutations = { RESET_EXTERNAL_PARAMETER_ESTIMATE_STATE: "resetExternalParameterEstimateState", RESET_EXTERNAL_PARAMETER_SERVICEZIP_STATE: "resetExternalParameterServiceZipState", RESET_EXTERNAL_PARAMETER_QUOTE_STATE: "resetExternalParameterQuoteState", + RESET_EXTERNAL_PARAMETER_SOURCE_STATE: "resetExternalParameterSourceState", RESET_IS_EXTERNAL_PARAMETER: "resetIsExternalParameter", //Affiliate Cookies diff --git a/src/store/index.js b/src/store/index.js index 6ed37e445..a724d26c1 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -912,6 +912,7 @@ export const getters = { externalParameterQuote: (state) => externalParameterState?.quote, externalParameterServiceZip: (state) => externalParameterState?.serviceZip, externalParameterEstimate: (state) => externalParameterState?.estimate, + externalParameterSource: (state) => externalParameterState?.source, }; function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) { @@ -2881,6 +2882,7 @@ export const actions = { context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_ESTIMATE_STATE); context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_SERVICEZIP_STATE); context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_QUOTE_STATE); + context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_SOURCE_STATE); context.commit(storeMutations.RESET_IS_EXTERNAL_PARAMETER); } }, From e7a3008b3a0e46bc7d74d127a04171499dd84f0e Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Fri, 20 Sep 2024 13:06:06 +0530 Subject: [PATCH 17/45] CSR-1629 CJ pixel tag event and batch event filter --- src/mixins/analytics-mixin.js | 87 +++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 615e5ecf6..eddf4463b 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -542,7 +542,7 @@ export default { let accountType = ""; let amount = 0; let cjEvent = ""; - if (store.getters.applicationUser.affiliateCookies) { + if (store.getters.applicationUser.affiliateCookies?.length > 0) { const affiliateCookies = store.getters.applicationUser.affiliateCookies; var cookieArray = []; affiliateCookies.forEach((item) => { @@ -554,48 +554,55 @@ export default { 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(); + const filteredCookie = sortedCookies?.find( + (x) => x.tagEvent?.length > 0 && x.batchEvent?.length > 0 + ); + if (filteredCookie?.length > 0) { + cjEvent = filteredCookie.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 (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 ?? []), - ]; + 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); + 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); + } } } } From bf8cf2d8bb33ceea9d6efcb1f89521f5c7aab8e9 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Fri, 20 Sep 2024 13:15:02 +0530 Subject: [PATCH 18/45] CSR-2228 Service package discount for CJ --- src/mixins/analytics-mixin.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 88ca626c9..3468c2985 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -416,11 +416,15 @@ export default { .getTotalPriceOfAllLineItemsAndChildParts([part], false) .toFixed(2); - if (productSku == "DISCOUNT") { + if (productSku == "DISCOUNT" || productType == "SERVICE PACKAGE DISCOUNT") { if (coupon) { coupon += ","; } - coupon += productSku; + if (productSku == "DISCOUNT") { + coupon += promoCode; + } else { + coupon += productSku; + } discount = discount + parseFloat(productPrice) * -1; } else { products.push({ From 25e3b8323564cc66da2f652b04697efe7b0890bc Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Fri, 20 Sep 2024 15:05:11 +0530 Subject: [PATCH 19/45] CSR-1629 fixed price subTotal --- src/mixins/analytics-mixin.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index eddf4463b..4f034c93c 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -409,31 +409,36 @@ export default { let productSku = part.partNumber; let productType = part.partType; let promoCode = part.promoCode; - let productPrice = baseMixin.methods - .getTotalPriceOfAllLineItemsAndChildParts([part], false) - .toFixed(2); + let productPrice = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts( + [part], + false + ); - if (productSku == "DISCOUNT") { + if (productSku == "DISCOUNT" || productType == "SERVICE PACKAGE DISCOUNT") { if (coupon) { coupon += ","; } - coupon += productSku; - discount = discount + parseFloat(productPrice) * -1; + if (productSku == "DISCOUNT") { + coupon += promoCode; + } else { + coupon += productSku; + } + discount += productPrice * -1; } else { products.push({ productType: productType, productSku: productSku, - productPrice: productPrice.toString(), + productPrice: productPrice.toFixed(2), productQuantity: "1", }); - subTotal += parseFloat(productPrice); + subTotal += productPrice; } } pushToDataLayerIfDefined({ productArray: { coupon: coupon, - discount: discount.toString(), - subTotal: subTotal.toString(), + discount: discount.toFixed(2), + subTotal: subTotal.toFixed(2), products: products, }, }); @@ -557,7 +562,7 @@ export default { const filteredCookie = sortedCookies?.find( (x) => x.tagEvent?.length > 0 && x.batchEvent?.length > 0 ); - if (filteredCookie?.length > 0) { + if (isDefined(filteredCookie)) { cjEvent = filteredCookie.tagEvent; const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder(); const submittedOrder = baseMixin.methods.getSubmittedOrder(); From 26b465f9ec0eb5f3f1cd40ec0139f75efc1705e6 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Fri, 20 Sep 2024 15:09:15 +0530 Subject: [PATCH 20/45] CSR-1629 formatting --- src/mixins/analytics-mixin.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index bb7317292..f219c5586 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -428,7 +428,6 @@ export default { } discount += productPrice * -1; - } else { products.push({ productType: productType, From 73553f82dbb63fe9d9a1ac276dfceb54086b13d7 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Fri, 20 Sep 2024 08:45:58 -0400 Subject: [PATCH 21/45] CSR-2202 CSR-2202 allow unverified insurance users to return to quote page --- src/layouts/quote/quote.vue | 66 +++++++++++++++---- .../service-location/service-location.vue | 3 +- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 660681da1..f98d4dab0 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -207,7 +207,10 @@ export default { ...servicePackageDiscountPart, ]; - // When calling pricing from the quote page, always use the cash parent account + // When calling pricing from the quote page, always use the cash parent account but save the existing one in case it's unverified insurance navigating backwards + var holdParentAccountNumber = store.getters.order.payment?.parentAccountNumber; + var holdBillToAccountNumber = store.getters.order.payment?.billToAccountNumber; + baseMixin.methods.dispatchStoreAction( storeActions.SAVE_PARENT_ACCOUNT_NUMBER, applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, @@ -260,6 +263,8 @@ export default { vm.lineItems = lineItems; vm.availableLineItems = pricingResults; vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue(vm.availableLineItems); + vm.holdParentAccountNumber = holdParentAccountNumber; + vm.holdBillToAccountNumber = holdBillToAccountNumber; if (revalidatePromoResponse) { const revalidateAlerts = buildToastMessagesFromRevalidateOrValidatePromoResponse( @@ -280,17 +285,10 @@ export default { ); } + // This is a safeguard to prevent verified insurance from seeing quote page again. const payment = store.getters.payment; - const policy = store.getters.policy; - if (payment?.isInsurance) { - const vehicleChangedDuringPolicyLookupInHeritage = - payment.insuranceCoverage?.coverageStatus && policy?.policyNumber !== ""; - - // This is a safeguard to prevent insurance from seeing quote page again. - // Usually this is caught in vehicle-questions-mixin with a referral length 6 check - if (vehicleChangedDuringPolicyLookupInHeritage) { - navigateToHeritageFunnel({ shouldSaveSession: true, pageNameToLog: "quote" }); - } + if (payment?.isInsurance && payment?.insuranceCoverage?.isVerified) { + navigateToHeritageFunnel({ shouldSaveSession: true, pageNameToLog: "quote" }); } if (store.getters.externalParameterState?.isExternalParameter) { @@ -319,6 +317,8 @@ export default { lineItems: [], addableVaps: [], servicePackage: null, + holdParentAccountNumber: null, + holdBillToAccountNumber: null, }; }, computed: { @@ -352,13 +352,44 @@ export default { this.$refs[modalName].openModal(); }, arePagePrerequisitesValid() { + const payment = store.getters.order.payment; + const log = getQuerystringParameter(queryStrings.LOG); + if (eval(log)) { + console.log("quote.vue pagePrereqs:"); + console.log( + new Date() + + " store.getters.order.serviceLocation.zipCode: " + + store.getters.order.serviceLocation?.zipCode + ); + console.log( + new Date() + + " store.getters.order.serviceLocation.zipCodeCtu: " + + store.getters.order.serviceLocation?.zipCodeCtu + ); + console.log( + new Date() + + " store.getters.order.damage.isRepair: " + + store.getters.order.damage?.isRepair + ); + console.log( + new Date() + + " store.getters.order.lineItems?.glassParts: " + + JSON.stringify(store.getters.order.lineItems?.glassParts) + ); + console.log( + new Date() + + " store.getters.order.payment.insuranceCoverage?.isVerified: " + + payment?.insuranceCoverage?.isVerified + ); + } return ( store.getters.order.serviceLocation.zipCode && store.getters.order.serviceLocation.zipCodeCtu && (store.getters.order.damage.isRepair || (store.getters.order.lineItems?.glassParts != null && store.getters.order.lineItems.glassParts.length > 0)) && - store.getters.order.referralNumber?.length !== 6 + (payment.insuranceCoverage?.isVerified == null || + payment.insuranceCoverage?.isVerified === false) ); }, getDefaultIsInsuranceSelectedValue(availableLineItems) { @@ -412,6 +443,17 @@ export default { applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER, false ); + } else { + baseMixin.methods.dispatchStoreAction( + storeActions.SAVE_PARENT_ACCOUNT_NUMBER, + this.holdParentAccountNumber, + false + ); + baseMixin.methods.dispatchStoreAction( + storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER, + this.holdBillToAccountNumber, + false + ); } if ( diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index badd8a204..022fa1183 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -503,7 +503,8 @@ export default { this.recalibrationInformationModal.openModal(); }, backButtonAction() { - if (store.getters.order.payment.isInsurance) { + const payment = store.getters.order.payment; + if (payment?.isInsurance && payment?.insuranceCoverage?.isVerified) { navigateToHeritageFunnel({ shouldSaveSession: false }); } else { this.$router.navigateWithoutSaving( From f0bf8edcd65bdef7cdb7a468b2e8de4f1d1b85e7 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Fri, 20 Sep 2024 09:10:34 -0400 Subject: [PATCH 22/45] CSR-2202 CSR-2202 tests --- src/layouts/quote/quote.spec.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index ca2bfd78e..d8e08a77d 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -169,12 +169,12 @@ describe("quote.vue", () => { damage: { isRepair: true, }, - referralNumber: "1234567", - }, - payment: { - insuranceCoverage: { - isVerified: false, + payment: { + insuranceCoverage: { + isVerified: false, + }, }, + referralNumber: "1234567", }, }; const { wrapper } = setupMocks({}); @@ -198,10 +198,10 @@ describe("quote.vue", () => { lineItems: { glassParts: ["item", "item2"], }, - }, - payment: { - insuranceCoverage: { - isVerified: false, + payment: { + insuranceCoverage: { + isVerified: false, + }, }, }, }; From ca6c05a65f22a0e28b913cc3f39c565cb25fba2c Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Fri, 20 Sep 2024 19:06:38 +0530 Subject: [PATCH 23/45] CSR-1629 CJ pixel amount format --- src/mixins/analytics-mixin.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index f219c5586..e0517080e 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -583,6 +583,15 @@ export default { ); coupons = promoString; } + const serviceZipPackage = submittedOrder.lineItems?.supportingItems?.find( + (x) => x.partType == "SERVICE PACKAGE DISCOUNT" + ); + if (isDefined(serviceZipPackage)) { + if (coupons) { + coupons += ","; + } + coupons += serviceZipPackage.partNumber; + } refSequenceNum = submittedOrder.referralSequenceNumber; if (isDefined(submittedOrder.payment.isInsurance)) { @@ -607,10 +616,10 @@ export default { isDefined(lineItem.sellingPrice) ); if (accountType == "cash" && isPricingAvailable) { - const quoteAmountWithDiscount = baseMixin.methods - .getTotalPriceOfAllLineItemsAndChildParts(combinedLineItems, false) - .toFixed(2); - amount = parseFloat(quoteAmountWithDiscount); + amount = baseMixin.methods.getTotalPriceOfAllLineItemsAndChildParts( + combinedLineItems, + false + ); } } } @@ -619,7 +628,7 @@ export default { commissionJunctionGtmData: { cj_commission_junction_event: cjEvent, cj_referral_sequence_number: refSequenceNum, - cj_amount: amount.toString(), + cj_amount: amount.toFixed(2), cj_repair_replace: repairReplace, cj_coupon: coupons, }, From 9bf5255f2b7dc7abc82f47e3486654e8dc8b98ea Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Fri, 20 Sep 2024 15:23:28 -0400 Subject: [PATCH 24/45] CSR-2166: refactoring to include logic to retrieve an insurance threshold from external parameters --- src/constants/experiments.js | 2 + src/layouts/quote/quote.vue | 90 ++++++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/constants/experiments.js b/src/constants/experiments.js index 52017ce47..eeabeb7d6 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -13,6 +13,8 @@ const experimentSettings = { IS_EMAIL_OPTIONAL: "isEmailOptional", SERVICE_PACKAGE_DISCOUNT: "OfferServicePackageDiscount", RECAL_PRICE_REMOVE: "RecalPriceRemove", + INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL: "NextGen_InternalInsuranceTabDisplayThreshold", + INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL: "NextGen_ExternalInsuranceTabDisplayThreshold", }; const experimentTriggers = { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index f98d4dab0..a5222b49b 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -135,6 +135,8 @@ import { packageNames } from "@/constants/package-names"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); +const INSURANCE_TAB_TO_DISPLAY_THRESHOLD_DEFAULT = 300; + export default { name: "quote", async beforeRouteEnter(to, from, next) { @@ -262,7 +264,6 @@ export default { vm.addableVaps = addableVaps; vm.lineItems = lineItems; vm.availableLineItems = pricingResults; - vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue(vm.availableLineItems); vm.holdParentAccountNumber = holdParentAccountNumber; vm.holdBillToAccountNumber = holdBillToAccountNumber; @@ -291,8 +292,51 @@ export default { navigateToHeritageFunnel({ shouldSaveSession: true, pageNameToLog: "quote" }); } - if (store.getters.externalParameterState?.isExternalParameter) { - if (store.getters.externalParameterQuote.isInsurance == true) { + const getIsInsuranceSelectedValue = (availableLineItems, insuranceThreshold) => { + const serviceLocationState = store.getters.order.serviceLocation.state; + // Override if coming back from QuoteDetails. Remove override after Quote release + const isInsuranceOverrideValue = to.query?.isInsurance; + + const defaultIsInsuranceSelectedValue = store.getters.order.payment.isInsurance; + //Default to Insurance Tab if user Service zip is from certain States + if ( + serviceLocationState != null && + payWithInsuranceStates.find((item) => item === serviceLocationState) + ) + return true; + else if (isInsuranceOverrideValue != null) { + return isInsuranceOverrideValue == "true"; + } else if (defaultIsInsuranceSelectedValue != null) { + return defaultIsInsuranceSelectedValue; + } else { + // TEMPORARY CODE WHILE DEVELOPING + if (availableLineItems) { + let tierOnePackagePriceTemp = baseMixin.methods.getTierOnePackagePrice( + baseMixin.methods.filterOutFees(availableLineItems) + ); + let whatToReturn = baseMixin.methods.getTierOnePackagePrice( + baseMixin.methods.filterOutFees(availableLineItems) + ) > insuranceThreshold; + return whatToReturn; // TODO AJC: TIGHTEN THIS BACK UP AFTER TESTING + } else { + return null; + } + } + }; + let thresholdToUse = INSURANCE_TAB_TO_DISPLAY_THRESHOLD_DEFAULT; + let internalThreshold = experimentMixin.methods.getSettingValue( + experimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL + ); + + if (!store.getters.externalParameterState?.isExternalParameter) { // there are no external parameters + + if (internalThreshold) thresholdToUse = internalThreshold; + vm.isInsuranceSelected = getIsInsuranceSelectedValue(vm.availableLineItems, thresholdToUse); + baseMixin.methods.ResetExternalParamsAndHideModal(); + + } else { // there ARE external parameters + + if (store.getters.externalParameterQuote.isInsurance == true) { // did user intentionally select insurance? vm.isInsuranceSelected = true; vm.servicePackage = store.getters.externalParameterQuote.servicePackage; await nextTick(); @@ -303,10 +347,22 @@ export default { baseMixin.methods.ResetExternalParamsAndHideModal(); } } else { + // did user come from external source (LeadGen)? + let externalSource = store.getters.externalParameterSource ? store.getters.externalParameterSource : null; + + // Business logic to determine what "external" source is + if (externalSource?.includes("LeadGen")) { + const externalThreshold = experimentMixin.methods.getSettingValue( + experimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL + ); + if (externalThreshold) thresholdToUse = externalThreshold; + } else { + if (internalThreshold) thresholdToUse = internalThreshold; + } + vm.isInsuranceSelected = getIsInsuranceSelectedValue(vm.availableLineItems, thresholdToUse); baseMixin.methods.ResetExternalParamsAndHideModal(); } - } else { - baseMixin.methods.ResetExternalParamsAndHideModal(); + } }); }, @@ -392,30 +448,6 @@ export default { payment.insuranceCoverage?.isVerified === false) ); }, - getDefaultIsInsuranceSelectedValue(availableLineItems) { - const serviceLocationState = store.getters.order.serviceLocation.state; - // Override if coming back from QuoteDetails. Remove override after Quote release - const isInsuranceOverrideValue = this.$route.query?.isInsurance; - - const defaultIsInsuranceSelectedValue = this.$store.getters.order.payment.isInsurance; - //Default to Insurance Tab if user Service zip is from certain States - if ( - serviceLocationState != null && - payWithInsuranceStates.find((item) => item === serviceLocationState) - ) - return true; - else if (isInsuranceOverrideValue != null) { - return isInsuranceOverrideValue == "true"; - } else if (defaultIsInsuranceSelectedValue != null) { - return defaultIsInsuranceSelectedValue; - } else { - return availableLineItems - ? baseMixin.methods.getTierOnePackagePrice( - baseMixin.methods.filterOutFees(availableLineItems) - ) > 300 - : null; - } - }, vapsItemsSelectedAction(vapsItemsSelected) { this.lineItems.vaps = vapsItemsSelected; }, From add23e716509068b71a97b9fd465dcc7ac5f55ef Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Fri, 20 Sep 2024 16:50:24 -0400 Subject: [PATCH 25/45] CSR-2166: fix unit test --- src/layouts/quote/quote.spec.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index d8e08a77d..ef5c945a3 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -391,12 +391,11 @@ describe("quote.vue", () => { }, }; const { wrapper } = setupMocks({}); - wrapper.vm.$route = { query: { isInsurance: "false" } }; //Act await quote.beforeRouteEnter.call( wrapper.vm, - { query: { fmgPage: "quote" } }, + { query: { fmgPage: "quote", isInsurance: false } }, undefined, (c) => c(wrapper.vm) ); From a6fadcb6772c14945257077e14fc3aea4e24c747 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Mon, 23 Sep 2024 10:10:54 -0400 Subject: [PATCH 26/45] CSR-1600 CSR-1600 clear work order number if ctu changes on referral with delete substatus used in pia. --- src/layouts/payment-method/payment-method.vue | 30 +++++++++---------- src/layouts/service-zip/service-zip.vue | 4 +-- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index ff7e6a8d8..0083efead 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -551,23 +551,21 @@ export default { }, async setupPia() { this.$refs.loadingModal.showModal(); - - // if we don't have a work order in delete substatus, set the flag and submit. // we need a work order number for pia so we can pass it to safeliteHop. - if (!store.getters.order.workOrderNumber) { - try { - await submitWorkOrder({ - pageNameToLog: "payment-method", - submitAfterSave: false, - createDeleteStatusWorkOrderForPia: true, - }); - } catch (error) { - console.log("error: response from pia submit work order:" + error.message); - this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); - this.$route.query[queryStrings.DISPLAY_PIA_ALERT] = true; - return; - } + // this will create one in delete substatus. + try { + await submitWorkOrder({ + pageNameToLog: "payment-method", + submitAfterSave: false, + createDeleteStatusWorkOrderForPia: true, + }); + } catch (error) { + console.log("error: response from pia submit work order:" + error.message); + this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); + this.$route.query[queryStrings.DISPLAY_PIA_ALERT] = true; + return; } + this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_PAY_NOW, @@ -594,7 +592,7 @@ export default { ); }, shouldHideRecalibration() { - return this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE); + return this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE).toLower() === "true"; }, showApplePay() { return baseMixin.methods.showApplePay(); diff --git a/src/layouts/service-zip/service-zip.vue b/src/layouts/service-zip/service-zip.vue index 34efac1a1..a60eb4aff 100644 --- a/src/layouts/service-zip/service-zip.vue +++ b/src/layouts/service-zip/service-zip.vue @@ -213,7 +213,7 @@ export default { const supportingItemsPromise = await this.dispatchStoreActionWithLogging( storeActions.GET_SUPPORTING_ITEMS, null, - "estimate" + "service-zip" ); const promiseResultMap = [ @@ -232,7 +232,7 @@ export default { ); // call saveSession here - navigateWithSaving saves too late in the flow - await saveSession({ pageNameToLog: "estimate" }); + await saveSession({ pageNameToLog: "service-zip" }); return this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_NO_QUESTIONS, this.$route From 0b7354d54ef2b57922faf1bcaabd076da64d8ca4 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Mon, 23 Sep 2024 10:43:34 -0400 Subject: [PATCH 27/45] CSR-1600 test CSR-1600 test --- src/layouts/payment-method/payment-method.vue | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 0083efead..89a31d454 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -565,7 +565,7 @@ export default { this.$route.query[queryStrings.DISPLAY_PIA_ALERT] = true; return; } - + this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_PAY_NOW, @@ -592,7 +592,9 @@ export default { ); }, shouldHideRecalibration() { - return this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE).toLower() === "true"; + return ( + this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE).toLowerCase() === "true" + ); }, showApplePay() { return baseMixin.methods.showApplePay(); From 2560787b4f4ea0fb3ada64409614b7f786d54b04 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 23 Sep 2024 13:50:47 -0400 Subject: [PATCH 28/45] CSR-2166: remove recal from calculation if experiment says it should be hidden --- src/layouts/quote/quote.vue | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index a5222b49b..76e206586 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -296,8 +296,11 @@ export default { const serviceLocationState = store.getters.order.serviceLocation.state; // Override if coming back from QuoteDetails. Remove override after Quote release const isInsuranceOverrideValue = to.query?.isInsurance; - const defaultIsInsuranceSelectedValue = store.getters.order.payment.isInsurance; + const hideRecalCost = experimentMixin.methods.getSettingValue( + experimentSettings.RECAL_PRICE_REMOVE + ); + //Default to Insurance Tab if user Service zip is from certain States if ( serviceLocationState != null && @@ -309,15 +312,18 @@ export default { } else if (defaultIsInsuranceSelectedValue != null) { return defaultIsInsuranceSelectedValue; } else { - // TEMPORARY CODE WHILE DEVELOPING if (availableLineItems) { - let tierOnePackagePriceTemp = baseMixin.methods.getTierOnePackagePrice( - baseMixin.methods.filterOutFees(availableLineItems) - ); - let whatToReturn = baseMixin.methods.getTierOnePackagePrice( - baseMixin.methods.filterOutFees(availableLineItems) - ) > insuranceThreshold; - return whatToReturn; // TODO AJC: TIGHTEN THIS BACK UP AFTER TESTING + + const lineItemsForCalculatingPrice = + (hideRecalCost === "true") ? + baseMixin.methods.filterOutFees( + baseMixin.methods.filterOutRecalibration(availableLineItems) // Strip out recal before filtering out fees + ) : + baseMixin.methods.filterOutFees(availableLineItems); + + let tierOnePackagePriceTemp = baseMixin.methods.getTierOnePackagePrice(lineItemsForCalculatingPrice); // TEMP, FOR TESTING /// TODO AJC: TIGHTEN THIS BACK UP AFTER TESTING + + return baseMixin.methods.getTierOnePackagePrice(lineItemsForCalculatingPrice) > insuranceThreshold; // compare base price vs arbitrary threshold (representing insurance price) } else { return null; } From 40ba5bb3b8b2856bfd51eb271b327f12fb2246fd Mon Sep 17 00:00:00 2001 From: CarlNation Date: Mon, 23 Sep 2024 14:04:47 -0400 Subject: [PATCH 29/45] CSR-1600 CSR-1600 rename pia field --- src/helpers/heritage-integration/order-helper.js | 14 +++++++------- src/layouts/payment-method/payment-method.vue | 5 +++-- src/router/index.js | 5 +---- src/store/index.js | 14 ++++++++++---- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/helpers/heritage-integration/order-helper.js b/src/helpers/heritage-integration/order-helper.js index 07c469ae8..555c41325 100644 --- a/src/helpers/heritage-integration/order-helper.js +++ b/src/helpers/heritage-integration/order-helper.js @@ -57,7 +57,7 @@ export async function saveSession({ pageNameToLog, shouldAwaitSaveSessionQueue = false, submitAfterSave = false, - createDeleteStatusWorkOrderForPia = false, + createUnscheduledStatusWorkOrderForPIA = false, }) { var saveSessionPromise; if (store.getters.applicationUser.saveSessionPromise) { @@ -67,7 +67,7 @@ export async function saveSession({ return saveSessionHelper( pageNameToLog, submitAfterSave, - createDeleteStatusWorkOrderForPia + createUnscheduledStatusWorkOrderForPIA ); }); } else { @@ -75,7 +75,7 @@ export async function saveSession({ saveSessionPromise = saveSessionHelper( pageNameToLog, submitAfterSave, - createDeleteStatusWorkOrderForPia + createUnscheduledStatusWorkOrderForPIA ); } store.commit(storeMutations.UPDATE_SAVE_SESSION_PROMISE, saveSessionPromise); @@ -88,13 +88,13 @@ export async function saveSession({ export async function submitWorkOrder({ pageNameToLog, submitAfterSave = false, - createDeleteStatusWorkOrderForPia = false, + createUnscheduledStatusWorkOrderForPIA = false, }) { await saveSession({ pageNameToLog: pageNameToLog, shouldAwaitSaveSessionQueue: true, submitAfterSave: submitAfterSave, - createDeleteStatusWorkOrderForPia: createDeleteStatusWorkOrderForPia, + createUnscheduledStatusWorkOrderForPIA: createUnscheduledStatusWorkOrderForPIA, }); } @@ -139,13 +139,13 @@ async function loadSession( async function saveSessionHelper( pageNameToLog, submitAfterSave = false, - createDeleteStatusWorkOrderForPia = false + createUnscheduledStatusWorkOrderForPIA = false ) { const savedSessionInfo = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.SAVE_SESSION, { submitAfterSave: submitAfterSave, - createDeleteStatusWorkOrderForPia: createDeleteStatusWorkOrderForPia, + createUnscheduledStatusWorkOrderForPIA: createUnscheduledStatusWorkOrderForPIA, }, pageNameToLog ); diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 89a31d454..9b7222bfc 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -557,7 +557,7 @@ export default { await submitWorkOrder({ pageNameToLog: "payment-method", submitAfterSave: false, - createDeleteStatusWorkOrderForPia: true, + createUnscheduledStatusWorkOrderForPIA: true, }); } catch (error) { console.log("error: response from pia submit work order:" + error.message); @@ -593,7 +593,8 @@ export default { }, shouldHideRecalibration() { return ( - this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE).toLowerCase() === "true" + this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE).toLowerCase() === "true" && + this.isRecalibrationOnOrder ); }, showApplePay() { diff --git a/src/router/index.js b/src/router/index.js index 266ccb855..4c57921b7 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -683,10 +683,7 @@ function updateExternalParameterState() { ); } if (externalParameterSource) { - store.commit( - storeMutations.UPDATE_EXTERNAL_PARAMETER_SOURCE, - externalParameterSource - ); + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_SOURCE, externalParameterSource); } } diff --git a/src/store/index.js b/src/store/index.js index a724d26c1..c0cb2e0e7 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -109,6 +109,7 @@ const getDefaultState = () => { insuranceCoverage: { isVerified: null, coverageStatus: null, + coverageSubStatus: null, coverageType: null, coverageVerificationType: null, }, @@ -690,6 +691,8 @@ export const mutations = { state.order.payment.insuranceCoverage.coverageStatus = coverageStatusValue( sessionInformation?.order.insuranceCoverage.coverageStatus ); + state.order.payment.insuranceCoverage.coverageSubStatus = + sessionInformation?.order.insuranceCoverage.coverageSubStatus; state.order.payment.insuranceCoverage.coverageType = coverageTypeValue( sessionInformation?.order.insuranceCoverage.coverageType ); @@ -1534,9 +1537,12 @@ export const actions = { ? context.getters.payment.billToAccountNumber : applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER; + const covStatus = context.getters.payment?.insuranceCoverage?.coverageStatus; + const covSubStatus = context.getters.payment?.insuranceCoverage?.coverageSubStatus; + return globalMethods.callHttpClient({ method: endpoints.GetMobileFeePart.method, - endpoint: `${endpoints.GetMobileFeePart.url}/${damageType}/${parentAccountNumber}/${billToAccountNumber}`, + endpoint: `${endpoints.GetMobileFeePart.url}/${damageType}/${parentAccountNumber}/${billToAccountNumber}/${covStatus}/${covSubStatus}`, logApiCall: true, pageNameToLog: pageNameToLog, }); @@ -1818,8 +1824,8 @@ export const actions = { const lineItems = context.state.order.lineItems; const submitAfterSave = payload?.submitAfterSave === "true"; - const createDeleteStatusWorkOrderForPia = - payload?.createDeleteStatusWorkOrderForPia === "true"; + const createUnscheduledStatusWorkOrderForPIA = + payload?.createUnscheduledStatusWorkOrderForPIA === "true"; // create a new array to avoid mutating state const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); @@ -1954,7 +1960,7 @@ export const actions = { referralNumber: order.referralNumber?.toString(), referralSequenceNumber: order.referralSequenceNumber, eon: order.eon, - createDeleteStatusWorkOrderForPia: createDeleteStatusWorkOrderForPia, + createUnscheduledStatusWorkOrderForPIA: createUnscheduledStatusWorkOrderForPIA, lockToken: order.lockToken, isRecalAckOptIn: order.isRecalAckOptIn, }, From e26fda362b7a81b5c425c29d00a33649b9adb87e Mon Sep 17 00:00:00 2001 From: CarlNation Date: Mon, 23 Sep 2024 14:36:16 -0400 Subject: [PATCH 30/45] CSR-1600 CSR-1600 spec file test --- src/helpers/heritage-integration/order-helper.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helpers/heritage-integration/order-helper.spec.js b/src/helpers/heritage-integration/order-helper.spec.js index daf9af6bb..ac8d08e9f 100644 --- a/src/helpers/heritage-integration/order-helper.spec.js +++ b/src/helpers/heritage-integration/order-helper.spec.js @@ -179,7 +179,7 @@ describe("saveSession", () => { // Assert expect(mocks.baseMixin.methods.dispatchStoreActionWithLogging).toHaveBeenCalledWith( storeActions.SAVE_SESSION, - { createDeleteStatusWorkOrderForPia: false, submitAfterSave: false }, + { createUnscheduledStatusWorkOrderForPIA: false, submitAfterSave: false }, "test" ); expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith( @@ -287,7 +287,7 @@ describe("submitWorkOrder", () => { // Assert expect(mocks.baseMixin.methods.dispatchStoreActionWithLogging).toHaveBeenCalledWith( storeActions.SAVE_SESSION, - { createDeleteStatusWorkOrderForPia: false, submitAfterSave: true }, + { createUnscheduledStatusWorkOrderForPIA: false, submitAfterSave: true }, "test" ); expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith( From 5e7bc8dc1338c6db1a8d01731dbc7ccd627d8a6d Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 23 Sep 2024 15:27:55 -0400 Subject: [PATCH 31/45] CSR-2166: some temporary debugging indications for dev --- src/layouts/quote/quote.vue | 13 +++++++++++++ .../service-package-question.vue | 11 ++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 76e206586..5d3db0c3a 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -15,6 +15,12 @@ +
+

thresholdToUse: {{ thresholdToUse }}

+

externalSource: {{ externalSource }}

+

recalSettingValue: {{ recalSettingValue }}

+
+ +
+ + +

isInsuranceSelected: {{ isInsuranceSelected }}

+

isRecalibrationOnOrder: {{ isRecalibrationOnOrder }}

+

shouldHideRecalibration: {{ shouldHideRecalibration }}

+ + +
{ From 784705041ae8799db2d4692b9fdee8060e6a3efe Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 23 Sep 2024 16:06:25 -0400 Subject: [PATCH 32/45] CSR-2166: EVEN MORE temporary debugging indications for dev --- src/layouts/quote/quote.vue | 3 ++- .../service-package-question/service-package-question.vue | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 5d3db0c3a..c9e1b3064 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -18,6 +18,7 @@

thresholdToUse: {{ thresholdToUse }}

externalSource: {{ externalSource }}

+

typeof recalSettingValue: {{ typeof recalSettingValue }}

recalSettingValue: {{ recalSettingValue }}


@@ -409,7 +410,7 @@ export default { shouldHideRecalibration() { const recalSettingValue = experimentMixin.methods.getSettingValue( experimentSettings.RECAL_PRICE_REMOVE - ); + ).toLowerCase() === "true"; return recalSettingValue; }, showAfterpayBanner() { diff --git a/src/layouts/quote/service-package-question/service-package-question.vue b/src/layouts/quote/service-package-question/service-package-question.vue index 2d8012aeb..b092ea65b 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -3,7 +3,9 @@

isInsuranceSelected: {{ isInsuranceSelected }}

+

typeof isRecalibrationOnOrder: {{ typeof isRecalibrationOnOrder }}

isRecalibrationOnOrder: {{ isRecalibrationOnOrder }}

+

typeof shouldHideRecalibration: {{ typeof shouldHideRecalibration }}

shouldHideRecalibration: {{ shouldHideRecalibration }}

From 00f34b7c3c3cc43f94df6b8837a43870b06a201c Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 23 Sep 2024 16:16:18 -0400 Subject: [PATCH 33/45] CSR-2166: fix for null exception error --- src/layouts/quote/quote.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index c9e1b3064..083862763 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -410,7 +410,7 @@ export default { shouldHideRecalibration() { const recalSettingValue = experimentMixin.methods.getSettingValue( experimentSettings.RECAL_PRICE_REMOVE - ).toLowerCase() === "true"; + )?.toLowerCase() === "true"; return recalSettingValue; }, showAfterpayBanner() { From 53d4a09a527e900d07c2137300cfe10dded90498 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 23 Sep 2024 18:09:30 -0400 Subject: [PATCH 34/45] CSR-2166: change all instances of hide recal setting from experiments to compare strings not boolean / reformatting --- src/layouts/confirmation/confirmation.vue | 5 +- src/layouts/payment-method/payment-method.vue | 5 +- src/layouts/quote/quote.vue | 60 ++++++++++++------- src/router/index.js | 5 +- 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/layouts/confirmation/confirmation.vue b/src/layouts/confirmation/confirmation.vue index acb97cba2..53851b251 100644 --- a/src/layouts/confirmation/confirmation.vue +++ b/src/layouts/confirmation/confirmation.vue @@ -170,7 +170,10 @@ export default { }, computed: { shouldHideRecalibration() { - return this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE); + const recalSettingValue = + this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE)?.toLowerCase() === + "true"; + return recalSettingValue; }, ShowCart() { if (this.isPia && this.submittedOrder?.settledTenderAmount == 0) { diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index ff7e6a8d8..de1c2670a 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -594,7 +594,10 @@ export default { ); }, shouldHideRecalibration() { - return this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE); + const recalSettingValue = + this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE)?.toLowerCase() === + "true"; + return recalSettingValue; }, showApplePay() { return baseMixin.methods.showApplePay(); diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 083862763..fd261483c 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -304,9 +304,10 @@ export default { // Override if coming back from QuoteDetails. Remove override after Quote release const isInsuranceOverrideValue = to.query?.isInsurance; const defaultIsInsuranceSelectedValue = store.getters.order.payment.isInsurance; - const hideRecalCost = experimentMixin.methods.getSettingValue( - experimentSettings.RECAL_PRICE_REMOVE - ); + const hideRecalCost = + experimentMixin.methods + .getSettingValue(experimentSettings.RECAL_PRICE_REMOVE) + ?.toLowerCase() === "true"; //Default to Insurance Tab if user Service zip is from certain States if ( @@ -320,17 +321,20 @@ export default { return defaultIsInsuranceSelectedValue; } else { if (availableLineItems) { + const lineItemsForCalculatingPrice = hideRecalCost + ? baseMixin.methods.filterOutFees( + baseMixin.methods.filterOutRecalibration(availableLineItems) // Strip out recal before filtering out fees + ) + : baseMixin.methods.filterOutFees(availableLineItems); - const lineItemsForCalculatingPrice = - (hideRecalCost === "true") ? - baseMixin.methods.filterOutFees( - baseMixin.methods.filterOutRecalibration(availableLineItems) // Strip out recal before filtering out fees - ) : - baseMixin.methods.filterOutFees(availableLineItems); + let tierOnePackagePriceTemp = baseMixin.methods.getTierOnePackagePrice( + lineItemsForCalculatingPrice + ); // TEMP, FOR TESTING /// TODO AJC: TIGHTEN THIS BACK UP AFTER TESTING - let tierOnePackagePriceTemp = baseMixin.methods.getTierOnePackagePrice(lineItemsForCalculatingPrice); // TEMP, FOR TESTING /// TODO AJC: TIGHTEN THIS BACK UP AFTER TESTING - - return baseMixin.methods.getTierOnePackagePrice(lineItemsForCalculatingPrice) > insuranceThreshold; // compare base price vs arbitrary threshold (representing insurance price) + return ( + baseMixin.methods.getTierOnePackagePrice(lineItemsForCalculatingPrice) > + insuranceThreshold + ); // compare base price vs arbitrary threshold (representing insurance price) } else { return null; } @@ -341,15 +345,20 @@ export default { experimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL ); - if (!store.getters.externalParameterState?.isExternalParameter) { // there are no external parameters + if (!store.getters.externalParameterState?.isExternalParameter) { + // there are no external parameters if (internalThreshold) thresholdToUse = internalThreshold; - vm.isInsuranceSelected = getIsInsuranceSelectedValue(vm.availableLineItems, thresholdToUse); + vm.isInsuranceSelected = getIsInsuranceSelectedValue( + vm.availableLineItems, + thresholdToUse + ); baseMixin.methods.ResetExternalParamsAndHideModal(); + } else { + // there ARE external parameters - } else { // there ARE external parameters - - if (store.getters.externalParameterQuote.isInsurance == true) { // did user intentionally select insurance? + if (store.getters.externalParameterQuote.isInsurance == true) { + // did user intentionally select insurance? vm.isInsuranceSelected = true; vm.servicePackage = store.getters.externalParameterQuote.servicePackage; await nextTick(); @@ -361,7 +370,9 @@ export default { } } else { // did user come from external source (LeadGen)? - let externalSource = store.getters.externalParameterSource ? store.getters.externalParameterSource : null; + let externalSource = store.getters.externalParameterSource + ? store.getters.externalParameterSource + : null; vm.externalSource = externalSource; // TEMP 9/23 @@ -374,10 +385,12 @@ export default { } else { if (internalThreshold) thresholdToUse = internalThreshold; } - vm.isInsuranceSelected = getIsInsuranceSelectedValue(vm.availableLineItems, thresholdToUse); + vm.isInsuranceSelected = getIsInsuranceSelectedValue( + vm.availableLineItems, + thresholdToUse + ); baseMixin.methods.ResetExternalParamsAndHideModal(); } - } vm.thresholdToUse = thresholdToUse; @@ -408,9 +421,10 @@ export default { ); }, shouldHideRecalibration() { - const recalSettingValue = experimentMixin.methods.getSettingValue( - experimentSettings.RECAL_PRICE_REMOVE - )?.toLowerCase() === "true"; + const recalSettingValue = + experimentMixin.methods + .getSettingValue(experimentSettings.RECAL_PRICE_REMOVE) + ?.toLowerCase() === "true"; return recalSettingValue; }, showAfterpayBanner() { diff --git a/src/router/index.js b/src/router/index.js index 266ccb855..4c57921b7 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -683,10 +683,7 @@ function updateExternalParameterState() { ); } if (externalParameterSource) { - store.commit( - storeMutations.UPDATE_EXTERNAL_PARAMETER_SOURCE, - externalParameterSource - ); + store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_SOURCE, externalParameterSource); } } From 3cd54358c661f01bc714478915a6a3bce300a57a Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 23 Sep 2024 18:18:45 -0400 Subject: [PATCH 35/45] CSR-2166: remove temp changes that were needed to test on dev --- src/layouts/quote/quote.vue | 18 ------------------ .../service-package-question.vue | 11 ----------- 2 files changed, 29 deletions(-) diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index fd261483c..2eefbb996 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -15,13 +15,6 @@ -
-

thresholdToUse: {{ thresholdToUse }}

-

externalSource: {{ externalSource }}

-

typeof recalSettingValue: {{ typeof recalSettingValue }}

-

recalSettingValue: {{ recalSettingValue }}

-
- insuranceThreshold @@ -374,8 +363,6 @@ export default { ? store.getters.externalParameterSource : null; - vm.externalSource = externalSource; // TEMP 9/23 - // Business logic to determine what "external" source is if (externalSource?.includes("LeadGen")) { const externalThreshold = experimentMixin.methods.getSettingValue( @@ -392,8 +379,6 @@ export default { baseMixin.methods.ResetExternalParamsAndHideModal(); } } - - vm.thresholdToUse = thresholdToUse; }); }, data() { @@ -405,9 +390,6 @@ export default { servicePackage: null, holdParentAccountNumber: null, holdBillToAccountNumber: null, - - thresholdToUse: null, // TEMP 9/23 - externalSource: null, // TEMP 9/23 }; }, computed: { diff --git a/src/layouts/quote/service-package-question/service-package-question.vue b/src/layouts/quote/service-package-question/service-package-question.vue index b092ea65b..6af6a31f5 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -1,15 +1,4 @@