From 8062894cca8070ac91462122bb4012a3743fab38 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 29 Jan 2024 21:23:55 -0500 Subject: [PATCH 01/54] CSR-1511: use coverage data from store --- src/store/index.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 0e93e6c4d..4d627e7e9 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1453,7 +1453,7 @@ export const actions = { ) { const order = context.state.order; const vehicle = context.state.order.vehicle; - + const payment = context.state.order.payment; let lineItems = [ ...(order.lineItems.supportingItems ?? []), ...(order.lineItems.vaps ?? []), @@ -1475,15 +1475,15 @@ export const actions = { endDate: endDate, shopAppointmentType: shopAppointmentType, applicationName: applicationConfig.APPLICATION_NAME, - parentAccountNumber: context.getters.payment.parentAccountNumber, + parentAccountNumber: payment.parentAccountNumber, carId: vehicle.carId, lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, coverage: { - status: "", - deductible: 0, - additionalAuthFlag: "", + status: payment.insuranceCoverage.coverageStatus, + deductible: order.policy.currentDeductible, + additionalAuthFlag: order.policy.additionalAuthFlag, }, partSelection: { hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length, @@ -1521,6 +1521,7 @@ export const actions = { getMobileTimeSlots(context, { payload: { startDate, endDate }, pageNameToLog }) { const order = context.state.order; const vehicle = context.state.order.vehicle; + const payment = context.state.order.payment; let lineItems = [ ...(order.lineItems.supportingItems ?? []), ...(order.lineItems.vaps ?? []), @@ -1539,15 +1540,15 @@ export const actions = { startDate: startDate, endDate: endDate, applicationName: applicationConfig.APPLICATION_NAME, - parentAccountNumber: context.getters.payment.parentAccountNumber, + parentAccountNumber: payment.parentAccountNumber, carId: vehicle.carId, lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, coverage: { - status: "", - deductible: 0, - additionalAuthFlag: "", + status: payment.insuranceCoverage.coverageStatus, + deductible: order.policy.currentDeductible, + additionalAuthFlag: order.policy.additionalAuthFlag, }, partSelection: { hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length, @@ -1566,6 +1567,7 @@ export const actions = { }, zipCode: order.serviceLocation.zipCode, }; + return globalMethods.callHttpClient({ method: endpoints.GetMobileTimeSlots.method, endpoint: endpoints.GetMobileTimeSlots.url, From 6839602ec032d7acd8f9fc44d17b6e4bdfaaced3 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Mon, 29 Jan 2024 22:03:41 -0500 Subject: [PATCH 02/54] CSR-1285: replace hard-coded account no. with State one --- src/store/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 4d627e7e9..bb4444062 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1343,7 +1343,7 @@ export const actions = { getMobileFeePart(context, { pageNameToLog }) { const damageType = context.getters.damage.isRepair ? "Repair" : "Replace"; const parentAccountNumber = context.getters.payment.parentAccountNumber; - const billToAccountNumber = 87291; // TODO: MAKE THIS REAL + const billToAccountNumber = context.getters.payment.billToAccountNumber; return globalMethods.callHttpClient({ method: endpoints.GetMobileFeePart.method, From 00b5038ff7b72406d7599d536bc01a13dafaa342 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Fri, 2 Feb 2024 08:50:20 -0500 Subject: [PATCH 03/54] CSR-1072 was not setting BillToAccount CSR-1072 was not setting BillToAccount --- src/store/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/store/index.js b/src/store/index.js index bb4444062..cdd5733ba 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -523,6 +523,8 @@ export const mutations = { state.order.payment.parentAccountNumber = sessionInformation.order.payment.parentAccountNumber; + state.order.payment.billToAccountNumber = + sessionInformation.order.payment.billToAccountNumber; state.order.payment.inactivePromos = sessionInformation.order.payment.inactivePromos; state.order.serviceLocation.address = From 364e85614b288e6b835ca95d3c76c45c486f336c Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Fri, 2 Feb 2024 13:25:25 -0500 Subject: [PATCH 04/54] CSR-1072 save coverage status value as string CSR-1072 save coverage status value as string --- src/constants/coverage-status.js | 18 ++++++++++++++++++ src/store/index.js | 6 ++++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/constants/coverage-status.js diff --git a/src/constants/coverage-status.js b/src/constants/coverage-status.js new file mode 100644 index 000000000..7cf757aed --- /dev/null +++ b/src/constants/coverage-status.js @@ -0,0 +1,18 @@ +const coverageStatus = { + PENDING: "Pending", + NOCOMP: "NoComp", + VERIFIED: "Verified", +}; + +export function coverageStatusValue(intCoverageStatus) { + switch (intCoverageStatus) { + case 0: + return coverageStatus.PENDING; + case 1: + return coverageStatus.NOCOMP; + case 2: + return coverageStatus.VERIFIED; + default: + return null; + } +} diff --git a/src/store/index.js b/src/store/index.js index cdd5733ba..5339f7973 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -29,6 +29,7 @@ import { } from "@/helpers/promotions-helper"; import { getDateDifferenceInDays } from "@/helpers/date-helper"; import sharedMutations from "./vuex-shared-mutations/vuexSharedMutations"; +import { coverageStatusValue } from "@/constants/coverage-status"; // Export State const getDefaultState = () => { return { @@ -559,8 +560,9 @@ export const mutations = { state.order.payment.isInsurance = sessionInformation.order.payment.isInsurance; state.order.payment.insuranceCoverage.isVerified = sessionInformation?.order.payment.insuranceCoverage.isVerified; - state.order.payment.insuranceCoverage.coverageStatus = - sessionInformation?.order.payment.insuranceCoverage.coverageStatus; + state.order.payment.insuranceCoverage.coverageStatus = coverageStatusValue( + sessionInformation?.order.payment.insuranceCoverage.coverageStatus + ); state.order.payment.insuranceCoverage.coverageVerificationType = sessionInformation?.order.payment.insuranceCoverage.coverageVerificationType; From a0acb7ffd470e0087d0d0f330c30c850e72e1889 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:19:21 -0500 Subject: [PATCH 05/54] CSR-1072 back button for end to end CSR-1072 back button for end to end should go back to heritage --- src/layouts/service-location/service-location.vue | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 4e890e531..bf9b9495c 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -138,6 +138,7 @@ import { getServiceabilityDetails, getShopProviderData, } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper"; +import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { Provider } from "@/layouts/service-location/classes/provider"; @@ -438,7 +439,14 @@ export default { this.recalibrationInformationModal.openModal(); }, backButtonAction() { - this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); + if (store.getters.order.payment.isInsurance) { + navigateToHeritageFunnel({shouldSaveSession: false}); + } else { + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_BACK, + this.$route + ); + } }, updateAndSaveSupportingItems() { const supportingItems = store.getters.lineItems.supportingItems; From 0d02b5cd7aca02f78ddee1122d06be79ed03ed9f Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:33:32 -0500 Subject: [PATCH 06/54] prettier --- src/layouts/service-location/service-location.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index bf9b9495c..a12e9ff78 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -440,7 +440,7 @@ export default { }, backButtonAction() { if (store.getters.order.payment.isInsurance) { - navigateToHeritageFunnel({shouldSaveSession: false}); + navigateToHeritageFunnel({ shouldSaveSession: false }); } else { this.$router.navigateWithoutSaving( this.navigationScenarios.CLICKED_BACK, From ac687e55454d448a9313cb3eb877c009d1d2453c Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 5 Feb 2024 20:40:23 +0530 Subject: [PATCH 07/54] CSR-1601 BillToAccountNumber --- src/constants/application-config.js | 1 + src/constants/store-actions.js | 1 + src/constants/store-mutations.js | 1 + src/global-methods.js | 7 +++++-- src/layouts/payment-method/payment-method.vue | 4 ++-- .../promo-modal-question/promo-modal-question.vue | 4 ++-- src/layouts/payment/payment.vue | 2 +- src/layouts/quote/quote.vue | 5 +++++ src/store/index.js | 8 ++++++++ 9 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/constants/application-config.js b/src/constants/application-config.js index 244882509..b8a59a129 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -11,6 +11,7 @@ const applicationConfig = { PAGE_QUERYSTRING: "fmgPage", SITE_ENTRY_TRIGGER_VALUE: "FixMyGlass", CASH_PARENT_ACCOUNT_NUMBER: 167132, + CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER: "87291", MY_ACCOUNT: process.env.VUE_APP_MY_ACCOUNT, PIA_RESPONSE_URL: location.protocol + diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 9b6fdb865..d77237170 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -80,6 +80,7 @@ const storeActions = { SAVE_PAYMENT_TYPE: "savePaymentType", SAVE_PAYMENT_METHOD_CHOICE: "savePaymentMethodChoice", SAVE_PARENT_ACCOUNT_NUMBER: "saveParentAccountNumber", + SAVE_BILL_TO_ACCOUNT_NUMBER: "saveBillToAccountNumber", SAVE_SUPPORTING_ITEMS: "saveSupportingItems", SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING: "saveSupportingItemsSuppressingStateResetting", diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index 5b0b66509..0b0338fef 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -46,6 +46,7 @@ const storeMutations = { UPDATE_REFERRAL_DATE: "updateReferralDate", UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId", UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber", + UPDATE_BILL_TO_ACCT_NUMBER: "updateBillToAcctNumber", UPDATE_EON: "updateEON", UPDATE_IS_INSURANCE: "updateIsInsurance", UPDATE_SAVED_SESSION_ID: "updateSavedSessionId", diff --git a/src/global-methods.js b/src/global-methods.js index f2821343d..1d145476b 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -22,10 +22,13 @@ export default { const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), }; - + const localhostserviceapi = "https://localhost:44317"; axios({ method: method, - url: cfDistroUrl + endpoint, + url: + (endpoint == "/schedule/api/v1/schedule/mobile-time-slots" + ? localhostserviceapi + : cfDistroUrl) + endpoint, data: payloadAndAnalyticsData, crossDomain: true, responseType: {}, diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 3bde800bf..75a8ffa0c 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -244,7 +244,7 @@ export default { const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - billToAccountNumber: "87291", + billToAccountNumber: store.getters.payment.billToAccountNumber, providerNumber: store.getters.order.serviceLocation.provider.providerNumber, appointmentType: store.getters.order.serviceLocation.appointmentType, serviceLocationCity: store.getters.order.serviceLocation.city, @@ -405,7 +405,7 @@ export default { await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - billToAccountNumber: "87291", + billToAccountNumber: store.getters.payment.billToAccountNumber, providerNumber: this.$store.getters.order.serviceLocation.provider.providerNumber, appointmentType: this.$store.getters.order.serviceLocation.appointmentType, diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue index b4b02b3ed..9bd92cec3 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue @@ -255,14 +255,14 @@ export default { this.availableVaps, "payment-method" ); - + console.log(store.getters.payment.billToAccountNumber); if (promoCodeData.isValid) { const pricedLineItemsToTax = []; pricedLineItemsToTax.push(...promoCodeData.promoCode); const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - billToAccountNumber: "87291", + billToAccountNumber: store.getters.payment.billToAccountNumber, providerNumber: store.getters.order.serviceLocation.provider.providerNumber, appointmentType: store.getters.order.serviceLocation.appointmentType, diff --git a/src/layouts/payment/payment.vue b/src/layouts/payment/payment.vue index 365dccf01..a0f888b04 100644 --- a/src/layouts/payment/payment.vue +++ b/src/layouts/payment/payment.vue @@ -356,7 +356,7 @@ export default { const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - billToAccountNumber: "87291", + billToAccountNumber: store.getters.payment.billToAccountNumber, providerNumber: store.getters.order.serviceLocation.provider.providerNumber, appointmentType: store.getters.order.serviceLocation.appointmentType, serviceLocationCity: store.getters.order.serviceLocation.city, diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 5c6b2d744..12ee04c8d 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -276,6 +276,11 @@ export default { applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, false ); + this.dispatchStoreAction( + this.storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER, + applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER, + false + ); } if ( diff --git a/src/store/index.js b/src/store/index.js index 5339f7973..e900f2093 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -249,6 +249,9 @@ export const mutations = { updateParentAcctNumber(state, parentAcctNumber) { state.order.payment.parentAccountNumber = parentAcctNumber; }, + updateBillToAcctNumber(state, billToAcctNumber) { + state.order.payment.billToAccountNumber = billToAcctNumber; + }, updateEON(state, eon) { state.order.eon = eon; }, @@ -1484,6 +1487,7 @@ export const actions = { lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, + billToAccountNumber: context.getters.payment.billToAccountNumber, coverage: { status: payment.insuranceCoverage.coverageStatus, deductible: order.policy.currentDeductible, @@ -1549,6 +1553,7 @@ export const actions = { lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, + billToAccountNumber: context.getters.payment.billToAccountNumber, coverage: { status: payment.insuranceCoverage.coverageStatus, deductible: order.policy.currentDeductible, @@ -2123,6 +2128,9 @@ export const actions = { saveParentAccountNumber(context, parentAccountNumber) { context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber); }, + saveBillToAccountNumber(context, billToAccountNumber) { + context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber); + }, saveSupportingItems(context, supportingItems) { if (!deepEqual(supportingItems, context.state.order.lineItems.supportingItems)) { From 80044b34c7ac58d5659dea1ffe2031ff54970bda Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 5 Feb 2024 20:52:05 +0530 Subject: [PATCH 08/54] Update global-methods.js --- src/global-methods.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/global-methods.js b/src/global-methods.js index 1d145476b..6da8c0b33 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -22,13 +22,9 @@ export default { const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), }; - const localhostserviceapi = "https://localhost:44317"; axios({ method: method, - url: - (endpoint == "/schedule/api/v1/schedule/mobile-time-slots" - ? localhostserviceapi - : cfDistroUrl) + endpoint, + url: cfDistroUrl + endpoint, data: payloadAndAnalyticsData, crossDomain: true, responseType: {}, From c644d3a7f8c556319481146a8cb009ecf8383201 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 5 Feb 2024 20:59:26 +0530 Subject: [PATCH 09/54] Revert "Update global-methods.js" --- src/global-methods.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/global-methods.js b/src/global-methods.js index 6da8c0b33..f2821343d 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -22,6 +22,7 @@ export default { const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), }; + axios({ method: method, url: cfDistroUrl + endpoint, From ed447dd7630d169c6c9ef20f1803827f7bbb9af6 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Mon, 5 Feb 2024 21:15:53 +0530 Subject: [PATCH 10/54] Update promo-modal-question.vue --- .../payment-method/promo-modal-question/promo-modal-question.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue index 9bd92cec3..adb9bee3d 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue @@ -255,7 +255,6 @@ export default { this.availableVaps, "payment-method" ); - console.log(store.getters.payment.billToAccountNumber); if (promoCodeData.isValid) { const pricedLineItemsToTax = []; pricedLineItemsToTax.push(...promoCodeData.promoCode); From 53d7aea7e103901097e4881b1db3efe2b8cd13d8 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Mon, 5 Feb 2024 15:27:35 -0500 Subject: [PATCH 11/54] CSR-1072 CSR-1072 the sessionId is not getting saved during loadsession. this is a problem when returning from heritage. the vuex sessionId ends up blank and we do not load the dynamoDb session data because we pass a default guid to load-session --- src/store/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/store/index.js b/src/store/index.js index 5339f7973..b61ea9084 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -577,6 +577,10 @@ export const mutations = { state.applicationUser.pageData = sessionInformation.applicationUser.pageData; state.applicationUser.lastPage = sessionInformation.applicationUser.lastPage; + if (sessionInformation.applicationUser.savedSessionId) { + state.applicationUser.savedSessionId = sessionInformation.applicationUser.savedSessionId; + } + state.order.schedule.date = sessionInformation.order.schedule?.date; state.order.schedule.startTime = sessionInformation.order.schedule?.startTime; state.order.schedule.endTime = sessionInformation.order.schedule?.endTime; From 4eea4d4af8b34a994e867f9ea54034e36da46043 Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Mon, 5 Feb 2024 15:33:55 -0500 Subject: [PATCH 12/54] prettier --- src/store/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index b61ea9084..86aa1a669 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -578,7 +578,8 @@ export const mutations = { state.applicationUser.lastPage = sessionInformation.applicationUser.lastPage; if (sessionInformation.applicationUser.savedSessionId) { - state.applicationUser.savedSessionId = sessionInformation.applicationUser.savedSessionId; + state.applicationUser.savedSessionId = + sessionInformation.applicationUser.savedSessionId; } state.order.schedule.date = sessionInformation.order.schedule?.date; From 48bb6ed7e7f2dfcfc88344261cbb4e00a2d4f6fb Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:27:31 -0500 Subject: [PATCH 13/54] CSR-1072 * Get set parentAccount in cookie correctly * Do not call order-items pricing when mobile fee returned no results * Allow insurance prereq to exclude supportingItems --- src/helpers/heritage-integration/cookie-helper.js | 2 +- .../service-location-helper.js | 4 ++++ src/layouts/service-location/service-location.vue | 12 ++++++++++-- src/store/index.js | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js index abb1c0a67..579993795 100644 --- a/src/helpers/heritage-integration/cookie-helper.js +++ b/src/helpers/heritage-integration/cookie-helper.js @@ -18,7 +18,7 @@ export function updateOrCreateFunnelCookie() { ReferralNumber: store.getters.order.referralNumber, ReferralDate: store.getters.order.referralDate, ReferralCorrelationId: store.getters.order.referralCorrelationId, - ReferralParentAccountNumber: store.getters.order.accountNumber, + ReferralParentAccountNumber: store.getters.order.payment.parentAccountNumber, HasDelayedClaimRegistration: wasClaimRegistrationDelayed, SuppressConceptFunnel: shouldSuppressConceptFunnel, SavedSessionId: store.getters.applicationUser.savedSessionId, 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 26f2e6962..6f65b2646 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 @@ -16,6 +16,10 @@ export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) { false ); + if (mobileFeePart.data === null || mobileFeePart.data === undefined || mobileFeePart.data === "") { + return null; + } + // Get the Mobile Fee Part Price const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 3d0d5f588..4096f4e1d 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -349,11 +349,19 @@ export default { }, methods: { arePagePrerequisitesValid() { - return ( + // insurance drops the recycle fee on replace orders so it won't be in supportingItems + if (store.getters.payment.isInsurance && !store.getters.order.damage.isRepair) { + return ( + store.getters.order.serviceLocation.zipCode !== null && + store.getters.payment.isInsurance !== null); + } + else { + return ( store.getters.lineItems.supportingItems !== null && store.getters.order.serviceLocation.zipCode !== null && store.getters.payment.isInsurance !== null - ); + ); + } }, setData(zipCodeData, serviceabilityDetails, mobileFeePart, shopProviderData) { if (zipCodeData) { diff --git a/src/store/index.js b/src/store/index.js index eeb70ec0a..cff4c71ea 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2229,6 +2229,7 @@ export const actions = { const vehicle = context.getters.order.vehicle; + // TODO: Insurance pricing...`ParentAccountNumber=${context.getters.order.payment.parentAccountNumber}` let queryString = `ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` + `&CTU=${ctuToUse}` + From 68b1cbc3c76ecb60e21d990b2e51f544bbc6708f Mon Sep 17 00:00:00 2001 From: CarlNation <32103961+CarlNation@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:33:34 -0500 Subject: [PATCH 14/54] prettier --- .../service-location-helper.js | 6 +++++- src/layouts/service-location/service-location.vue | 14 +++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) 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 6f65b2646..e92349ddf 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 @@ -16,7 +16,11 @@ export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) { false ); - if (mobileFeePart.data === null || mobileFeePart.data === undefined || mobileFeePart.data === "") { + if ( + mobileFeePart.data === null || + mobileFeePart.data === undefined || + mobileFeePart.data === "" + ) { return null; } diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 4096f4e1d..38f46424f 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -352,14 +352,14 @@ export default { // insurance drops the recycle fee on replace orders so it won't be in supportingItems if (store.getters.payment.isInsurance && !store.getters.order.damage.isRepair) { return ( - store.getters.order.serviceLocation.zipCode !== null && - store.getters.payment.isInsurance !== null); - } - else { + store.getters.order.serviceLocation.zipCode !== null && + store.getters.payment.isInsurance !== null + ); + } else { return ( - store.getters.lineItems.supportingItems !== null && - store.getters.order.serviceLocation.zipCode !== null && - store.getters.payment.isInsurance !== null + store.getters.lineItems.supportingItems !== null && + store.getters.order.serviceLocation.zipCode !== null && + store.getters.payment.isInsurance !== null ); } }, From acd68f97d958f207cc2c93f801866bbbee91006c Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 7 Feb 2024 16:02:22 -0500 Subject: [PATCH 15/54] Auto-route only as far as Quote for cash users. --- .../heritage-integration/navigation-helper.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index 8fdfc40bb..bd2525ac2 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -123,17 +123,21 @@ async function getLatestPageForRedirection() { const scheduleComponent = await getLazyLoadedComponent(fmgPageValues.SCHEDULE); const skipVin = await skipVinLookup(); + const isInsuranceUser = !!store.getters.order.payment.isInsurance; if (!vehicleDamageComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE; } else if (!estimateComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE_DAMAGE; } else { - if (scheduleComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.SCHEDULE; - } else if (serviceLocationComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.SERVICE_LOCATION; - } else if (quoteComponent.methods.arePagePrerequisitesValid()) { + if (isInsuranceUser) { + if (scheduleComponent.methods.arePagePrerequisitesValid()) { + return fmgPageValues.SCHEDULE; + } else if (serviceLocationComponent.methods.arePagePrerequisitesValid()) { + return fmgPageValues.SERVICE_LOCATION; + } + } + if (quoteComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.QUOTE; } else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.CAPABILITY_QUESTIONS; From 5e09c22e3388c86d2ee80473de0f875bae4b7749 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Wed, 7 Feb 2024 18:24:35 -0500 Subject: [PATCH 16/54] CSR-1952: include promo cart items into selected package cart items --- src/fmg-components/cart/cart.vue | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index 2d268e81a..65701db71 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -167,6 +167,12 @@ export default { }); }); + if (this.promoCartItems) { + this.promoCartItems.forEach((promoCartItem) => { + vapsCartItemsForSelectedPackage.push(promoCartItem); + }); + } + return vapsCartItemsForSelectedPackage; }, getCmsContentForVapsType(vapsType) { From 11b7f52c8fd7feae1bb8684556e918d55df13793 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 8 Feb 2024 10:51:33 -0500 Subject: [PATCH 17/54] Also remove ability for non-cash users to be routed past quote. --- src/helpers/heritage-integration/navigation-helper.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index bd2525ac2..80734adf8 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -123,20 +123,12 @@ async function getLatestPageForRedirection() { const scheduleComponent = await getLazyLoadedComponent(fmgPageValues.SCHEDULE); const skipVin = await skipVinLookup(); - const isInsuranceUser = !!store.getters.order.payment.isInsurance; if (!vehicleDamageComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE; } else if (!estimateComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE_DAMAGE; } else { - if (isInsuranceUser) { - if (scheduleComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.SCHEDULE; - } else if (serviceLocationComponent.methods.arePagePrerequisitesValid()) { - return fmgPageValues.SERVICE_LOCATION; - } - } if (quoteComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.QUOTE; } else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) { From 2dc8d429714fc776f45cdd56b2552b2cedcea8d7 Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Fri, 9 Feb 2024 20:51:11 +0530 Subject: [PATCH 18/54] CSR-1438 make email optional --- src/constants/experiments.js | 1 + .../textbox-question/textbox-question.vue | 8 +++++++- .../address-lookup/address-lookup.spec.js | 13 +++++++++++++ src/layouts/address-lookup/address-lookup.vue | 6 +++++- .../customer-questions/customer-questions.vue | 5 ++++- src/layouts/estimate/estimate.spec.js | 17 +++++++++++++++-- src/layouts/estimate/estimate.vue | 5 +++-- .../license-plate-lookup.spec.js | 14 ++++++++++++-- .../license-plate-lookup.vue | 4 +++- src/layouts/vin-lookup/vin-lookup.spec.js | 7 +++++++ src/layouts/vin-lookup/vin-lookup.vue | 5 +++-- src/mixins/vin-pages-mixin.js | 12 ++++++++++++ 12 files changed, 85 insertions(+), 12 deletions(-) diff --git a/src/constants/experiments.js b/src/constants/experiments.js index b702b11bb..18ca6387d 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -8,6 +8,7 @@ const experimentSettings = { DISPLAY_AVAILABILITY_INDICATORS: "DisplayAvailabilityIndicators", PIA_EXPERIENCE: "PIA Experience", SUBMIT_ORDER_ENABLE_PIA: "SubmitOrder_Enable_PIA", + IS_EMAIL_OPTIONAL: "isEmailOptional", }; const experimentTriggers = { diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 11f232135..da41fe10b 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -121,6 +121,10 @@ export default { hideInput: Boolean, centerErrorMessage: Boolean, keyDownHandler: Function, + isEmailOptional: { + type: Boolean, + default: false, + }, }, setup(props) { const uuid = uuidv4(); @@ -193,7 +197,9 @@ export default { }, computed: { questionText() { - return this.getCmsContent(this.cmsWidgetName, "QuestionText"); + return this.isEmailOptional + ? this.getCmsContent(this.cmsWidgetName, "QuestionText") + " (optional)" + : this.getCmsContent(this.cmsWidgetName, "QuestionText"); }, value: { get: function () { diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js index cce68d793..731e664dc 100644 --- a/src/layouts/address-lookup/address-lookup.spec.js +++ b/src/layouts/address-lookup/address-lookup.spec.js @@ -10,6 +10,7 @@ import { storeMutations } from "@/constants/store-mutations"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; import store from "@/store"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; +import { experimentSettings } from "@/constants/experiments"; jest.mock("@/helpers/damage-helper", () => ({ isGlassAvailableForCarId: jest.fn().mockImplementation(() => true), @@ -641,6 +642,17 @@ describe("address-lookup.vue", () => { }); }); +const mockMixin = { + methods: { + getSettingValue: jest.fn((settingName) => { + if (settingName === experimentSettings.IS_EMAIL_OPTIONAL) { + return "true"; + } + return "false"; + }), + }, +}; + function setupMocks({ isZipValid = true, isZipServiceable = true, @@ -709,6 +721,7 @@ function setupMocks({ }, }, }, + mixins: [mockMixin], }) ); diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index de0e8d5aa..807bdc5ce 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -20,7 +20,11 @@ - + + :isRequired="!isEmailOptional" + :validationRules="validationRules" + :isEmailOptional="isEmailOptional" />
@@ -79,6 +81,7 @@ export default { }), }, validationRules: String, + isEmailOptional: Boolean, }, computed: { customerModel: { diff --git a/src/layouts/estimate/estimate.spec.js b/src/layouts/estimate/estimate.spec.js index 7d395e88d..b8517d833 100644 --- a/src/layouts/estimate/estimate.spec.js +++ b/src/layouts/estimate/estimate.spec.js @@ -11,6 +11,7 @@ import { settleAllPromises } from "@/helpers/layout-helper.js"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import baseMixin from "../../mixins/base-mixin"; import { vinLookupMethodSelections } from "@/constants/vin-lookup-method-selections.js"; +import { experimentSettings } from "@/constants/experiments"; // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ @@ -273,12 +274,24 @@ function setupMocks({ Answers: cmsAnswers, FunnelFooterWidget: FunnelFooterWidget, }; - + const mockMixin = { + methods: { + getSettingValue: jest.fn((settingName) => { + if (settingName === experimentSettings.IS_EMAIL_OPTIONAL) { + return "true"; + } + return "false"; + }), + }, + }; const apiPromise = Promise.resolve({ cmsContent }); settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - const mountOptions = getMountOptions({ ...mountOptionsMockData, mixins: [baseMixin] }); + const mountOptions = getMountOptions({ + ...mountOptionsMockData, + mixins: [baseMixin, mockMixin], + }); mountOptions["attachTo"] = document.body; const wrapper = shallowMount(estimate, mountOptions); diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index 410c4d325..d2766f730 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -52,9 +52,10 @@ cmsWidgetName="EmailAddressQuestionWidget" v-model="emailAddress" inputId="emailAddress" - isRequired + :isRequired="!IsEmailOptional" disableAutoFill - validationRules="email-address-required|email-address-format" /> + :validationRules="EmailValidationRules" + :isEmailOptional="IsEmailOptional" /> "loader.gif"); jest.mock("@/assets/img/windshield.png", () => "windshield.png"); @@ -692,11 +693,20 @@ function setupMocks({ }; const apiPromise = Promise.resolve(apiResponses); - + const mockMixin = { + methods: { + getSettingValue: jest.fn((settingName) => { + if (settingName === experimentSettings.IS_EMAIL_OPTIONAL) { + return "true"; + } + return "false"; + }), + }, + }; settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - const mountOptions = getMountOptions(mountOptionsMockData); + const mountOptions = getMountOptions({ ...mountOptionsMockData, mixins: [mockMixin] }); mountOptions["attachTo"] = document.body; // append wrapper to document.body to test DOM methods const wrapper = shallowMount(licensePlateLookup, mountOptions); diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index 811dbea7b..37d93cc8b 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -34,7 +34,9 @@ cmsWidgetName="EmailAddressQuestionWidget" v-model="email" customInputId="email" - validationRules="email-address-required|email-address-format" /> + :isRequired="!IsEmailOptional" + :validationRules="EmailValidationRules" + :isEmailOptional="IsEmailOptional" /> diff --git a/src/layouts/vin-lookup/vin-lookup.spec.js b/src/layouts/vin-lookup/vin-lookup.spec.js index f25bc68db..1d7d3f493 100644 --- a/src/layouts/vin-lookup/vin-lookup.spec.js +++ b/src/layouts/vin-lookup/vin-lookup.spec.js @@ -3,6 +3,7 @@ import vinLookup from "./vin-lookup.vue"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios.js"; import { settleAllPromises } from "@/helpers/layout-helper.js"; +import { experimentSettings } from "@/constants/experiments"; import store from "@/store"; @@ -378,5 +379,11 @@ function mockOutStubFunctions(wrapper) { const mockMixin = { methods: { getCmsContent: jest.fn(() => "placeholder CMS content"), + getSettingValue: jest.fn((settingName) => { + if (settingName === experimentSettings.IS_EMAIL_OPTIONAL) { + return "true"; + } + return "false"; + }), }, }; diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index c809bae70..ae197aeb0 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -53,8 +53,9 @@ cmsWidgetName="EmailAddressQuestionWidget" v-model="emailAddress" customInputId="emailAddress" - isRequired - validationRules="email-address-required|email-address-format" /> + :isRequired="!IsEmailOptional" + :validationRules="EmailValidationRules" + :isEmailOptional="IsEmailOptional" /> diff --git a/src/mixins/vin-pages-mixin.js b/src/mixins/vin-pages-mixin.js index a0a435000..98eb7a75b 100644 --- a/src/mixins/vin-pages-mixin.js +++ b/src/mixins/vin-pages-mixin.js @@ -2,8 +2,20 @@ import { storeActions } from "@/constants/store-actions.js"; import store from "@/store"; import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; +import { experimentSettings } from "@/constants/experiments"; export default { + computed: { + IsEmailOptional() { + const emailOptional = this.getSettingValue(experimentSettings.IS_EMAIL_OPTIONAL); + return emailOptional === "true"; + }, + EmailValidationRules() { + return this.IsEmailOptional + ? "email-address-format" + : "email-address-required|email-address-format"; + }, + }, methods: { async navigateForwardWithSingleCarMatch() { const pageName = this.$options?.name; From 37a59cc74e4e221b5e3a1884836d359863f5ebea Mon Sep 17 00:00:00 2001 From: Sneha Date: Fri, 9 Feb 2024 21:27:13 +0530 Subject: [PATCH 19/54] merge to release --- src/layouts/payment-method/payment-method.vue | 1 + .../promo-modal-question.spec.js | 143 ++++++++++++++++++ .../promo-modal-question.vue | 76 ++++++---- src/layouts/quote/quote.spec.js | 33 +++- src/layouts/quote/quote.vue | 75 +++++++-- .../service-package-question.spec.js | 51 +++++++ .../service-package-question.vue | 3 + 7 files changed, 334 insertions(+), 48 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 3bde800bf..ee0eee749 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -33,6 +33,7 @@ class="small mt-4" v-model="lineItems" :availableVaps="availableVaps" + pageName="payment-method" modalWidgetName="PromoModalWidget" />
diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js b/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js index 16d170e82..1dcc2ac70 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js @@ -1,5 +1,25 @@ import { mount, shallowMount } from "@vue/test-utils"; import promoModalQuestion from "./promo-modal-question"; +import { storeActions } from "@/constants/store-actions"; +import baseMixin from "@/mixins/base-mixin.js"; + +let mockReturnsForStoreActions = {}; + +jest.mock("@/mixins/base-mixin", () => ({ + ...jest.requireActual("@/mixins/base-mixin"), + methods: { + dispatchStoreActionWithLogging: jest.fn( + (action, { promoCode, addableVaps }, pageNameToLog, someBool) => { + return mockReturnsForStoreActions[action]; + } + ), + }, +})); + +afterEach(() => { + // reset store action returns + mockReturnsForStoreActions = {}; +}); jest.mock("@/digital-components/textbox-question/textbox-question", () => ({ getCmsContent: jest.fn((widgetName, cmsFieldName) => { @@ -79,4 +99,127 @@ describe("promo-modal-question.vue", () => { // Assert expect(wrapper.emitted("update:modelValue")).toEqual([[lineItems]]); }); + it("focuses on the input element when focusOnPromoInput is called", async () => { + // Arrange + const lineItems = { + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }; + + const wrapper = mount(promoModalQuestion, { + mixins: [mockMixin], + props: { + modelValue: lineItems, + modalWidgetName: modalWidgetName, + }, + attachTo: document.body, + }); + const focusMock = jest.fn(); + const inputMock = { focus: focusMock }; + + // Mock document.getElementById to return the inputMock + jest.spyOn(document, "getElementById").mockReturnValue(inputMock); + + //Act + + wrapper.vm.focusOnPromoInput(); + await wrapper.vm.$nextTick(); + + //Assert + expect(focusMock).toHaveBeenCalled(); + }); + it("returns a validate response on applying promo", async () => { + // Arrange + const newPromo = "testPromo"; + const pageNameToLog = "testPage"; + const validateResponse = { orderPromos: [] }; + const addableVaps = []; + mockReturnsForStoreActions[storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA] = + validateResponse; + const lineItems = { + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }; + + const wrapper = mount(promoModalQuestion, { + mixins: [mockMixin], + props: { + modelValue: lineItems, + modalWidgetName: modalWidgetName, + }, + attachTo: document.body, + }); + // Act + + wrapper.vm.getPromoCodeData(); + + const promoValidationResponse = await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA, + { + newPromo, + lineItems, + addableVaps, + }, + pageNameToLog, + false + ); + + // Assert + expect(promoValidationResponse).toEqual(validateResponse); + }); + test("If promocode is valid return taxed lineItems", async () => { + //Arrange + const taxedlineItems = {}; + + mockReturnsForStoreActions[storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA] = + taxedlineItems; + + const lineItems = { + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }; + + let promoCode = "1wiper0"; + const pricedLineItemsToTax = []; + + pricedLineItemsToTax.push(promoCode); + const wrapper = mount(promoModalQuestion, { + mixins: [mockMixin], + + props: { + modelValue: lineItems, + modalWidgetName: modalWidgetName, + }, + + attachTo: document.body, + }); + wrapper.vm.addPromoCode(); + + const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, + { + billToAccountNumber: "87291", + providerNumber: 2, + appointmentType: "IN_SHOP", + serviceLocationCity: "city", + serviceLocationState: "state", + serviceLocationZipCode: "12345", + pricedLineItems: pricedLineItemsToTax, + }, + + "payment-method", + + false + ); + + // Assert + + expect(taxedLineItems).toEqual(taxedlineItems); + }); }); diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue index b4b02b3ed..da8d344e9 100644 --- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue +++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue @@ -100,6 +100,12 @@ export default { modelValue: Object, modalWidgetName: String, availableVaps: Object, + pageName: String, + taxPromos: { + type: Boolean, + required: false, + default: true, + }, }, computed: { promoLinkText() { @@ -253,44 +259,52 @@ export default { this.promoCode, this.lineItems, this.availableVaps, - "payment-method" + this.pageName ); if (promoCodeData.isValid) { - const pricedLineItemsToTax = []; - pricedLineItemsToTax.push(...promoCodeData.promoCode); - const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( - storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, - { - billToAccountNumber: "87291", - providerNumber: - store.getters.order.serviceLocation.provider.providerNumber, - appointmentType: store.getters.order.serviceLocation.appointmentType, - serviceLocationCity: store.getters.order.serviceLocation.city, - serviceLocationState: store.getters.order.serviceLocation.state, - serviceLocationZipCode: store.getters.order.serviceLocation.zipCode, - pricedLineItems: pricedLineItemsToTax, - }, - "payment-method", - false - ); + if (this.taxPromos) { + const pricedLineItemsToTax = []; + pricedLineItemsToTax.push(...promoCodeData.promoCode); + const taxedLineItems = + await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, + { + billToAccountNumber: "87291", + providerNumber: + store.getters.order.serviceLocation.provider.providerNumber, + appointmentType: + store.getters.order.serviceLocation.appointmentType, + serviceLocationCity: store.getters.order.serviceLocation.city, + serviceLocationState: store.getters.order.serviceLocation.state, + serviceLocationZipCode: + store.getters.order.serviceLocation.zipCode, + pricedLineItems: pricedLineItemsToTax, + }, + "payment-method", + false + ); - // Match all line items to the line items as they are in the store - // and rebuild the original structure. - this.lineItems = mapTaxedLineItemsToStoreFormat(taxedLineItems, this.lineItems); - const taxedVaps = mapTaxedLineItemsToStoreFormat( - taxedLineItems, - this.availableVaps - ); + // Match all line items to the line items as they are in the store + // and rebuild the original structure. + this.lineItems = mapTaxedLineItemsToStoreFormat( + taxedLineItems, + this.lineItems + ); + const taxedVaps = mapTaxedLineItemsToStoreFormat( + taxedLineItems, + this.availableVaps + ); - const getVaps = getVapsThatNeedToBeAddedToSatisfyPromos( - promoCodeData.promoCode, - taxedVaps, - this.lineItems - ); + const getVaps = getVapsThatNeedToBeAddedToSatisfyPromos( + promoCodeData.promoCode, + taxedVaps, + this.lineItems + ); + this.lineItems.vaps?.push(...getVaps); + } this.lineItems?.promos.push(...promoCodeData.promoCode); - this.lineItems.vaps?.push(...getVaps); this.closeModal(); } else { this.getErrorMessage(promoCodeData.errorCode, promoCodeData.additionalInfo); diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index dc30985a5..be68267ae 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -133,8 +133,6 @@ describe("quote.vue", () => { }; }); - wrapper.vm.pricedGlassParts = []; - //Act await wrapper.vm.forwardButtonAction(); @@ -172,8 +170,6 @@ describe("quote.vue", () => { }; }); - wrapper.vm.pricedGlassParts = []; - //Act await wrapper.vm.forwardButtonAction(); @@ -288,8 +284,8 @@ describe("quote.vue", () => { ); //Assert - expect(wrapper.vm.pricedGlassParts !== null).toBe(true); - expect(wrapper.vm.supportingItems !== null).toBe(true); + expect(wrapper.vm.lineItems !== null).toBe(true); + expect(wrapper.vm.availableVaps !== null).toBe(true); expect(wrapper.vm.availableLineItems !== null).toBe(true); // This should have its own test //expect(vm.isInsuranceSelected !== null).toBe(true); @@ -548,6 +544,31 @@ describe("quote.vue", () => { //Assert expect(wrapper.vm.isInsuranceSelected).toBe(true); }); + test("On forward button action save promos", async () => { + //Arrange + store.getters.payment = { + insuranceCoverage: {}, + isInsurance: false, + }; + store.getters.order = { + lineItems: [], + payment: { + parentAccountNumber: 167132, + }, + }; + const { wrapper } = setupMocks({ + customMountOptions: { + router: { + navigateWithSaving: jest.fn(), + }, + route: { quote }, + }, + }); + + wrapper.vm.forwardButtonAction(); + + expect(wrapper.vm.lineItems.promos !== null).toBe(true); + }); }); function setupMocks({ customMountOptions }) { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 5c6b2d744..8d3dbcee3 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -39,6 +39,15 @@ cmsWidgetName="AfterpayModalWidget" :lineItems="availableLineItems" /> + + { vm.setCmsContent(resultMap.cmsContent); - vm.pricedGlassParts = nullSafeGlassParts; - vm.supportingItems = resultMap.supportingItems; + vm.availableVaps = availableVaps; + vm.lineItems = lineItems; vm.availableLineItems = pricingResults; vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue(vm.availableLineItems); @@ -208,15 +224,17 @@ export default { data() { return { isInsuranceSelected: null, - selectedVaps: null, availableLineItems: null, - supportingItems: null, - pricedGlassParts: null, + lineItems: [], + availableVaps: [], }; }, computed: { allActivePromos() { - return this.$store.getters.order.lineItems.promos ?? []; + return this.lineItems.promos ?? []; + }, + lineItemsCloneForWatcher() { + return Object.assign({}, this.lineItems); }, }, methods: { @@ -258,7 +276,7 @@ export default { } }, vapsItemsSelectedAction(vapsItemsSelected) { - this.selectedVaps = vapsItemsSelected; + this.lineItems.vaps = vapsItemsSelected; }, backButtonAction() { vehicleQuestionsMixin.methods.navigateBack(this); @@ -285,15 +303,23 @@ export default { this.supportingItems = this.filterOutFees(this.supportingItems); } - if (this.pricedGlassParts.length > 0) { + if (this.lineItems.glassParts?.length > 0) { this.dispatchStoreAction( this.storeActions.SAVE_GLASS_PARTS_SUPPRESSING_STATE_RESETTING, - this.pricedGlassParts, + this.lineItems.glassParts, false ); } - this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false); + this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.lineItems.vaps, false); + this.dispatchStoreAction( + storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, + { + activePromos: this.lineItems.promos, + inactivePromos: this.$store.getters.order.payment.inactivePromos, + }, + false + ); const payment = this.$store.getters.payment; if (payment.isInsurance) { @@ -310,6 +336,32 @@ export default { } }, }, + watch: { + lineItemsCloneForWatcher: { + handler(newValue, oldValue) { + if ( + !oldValue || + oldValue.length == 0 || + !oldValue.vaps || + !newValue || + newValue.length == 0 + ) { + return; + } + if (oldValue.promos.length < newValue.promos.length) { + const oldPromoCodes = oldValue.promos.map( + (promoObject) => promoObject.promoCode + ); + const newlyActivatedPromoCodes = newValue.promos.filter( + (newPromo) => !oldPromoCodes.includes(newPromo.promoCode) + ); + const alert = createPromoSuccessAlert(newlyActivatedPromoCodes[0].promoCode); + this.$refs.funnelHeader.pushGlobalAlert(alert, alert.shouldAutoFade); + } + }, + deep: true, + }, + }, components: { funnelHeader, navbar, @@ -322,6 +374,7 @@ export default { contentGroupModal, loadingModal, afterpayModalBanner, + promoModalQuestion, }, }; diff --git a/src/layouts/quote/service-package-question/service-package-question.spec.js b/src/layouts/quote/service-package-question/service-package-question.spec.js index c156ef34c..8163c6324 100644 --- a/src/layouts/quote/service-package-question/service-package-question.spec.js +++ b/src/layouts/quote/service-package-question/service-package-question.spec.js @@ -256,6 +256,57 @@ describe("service-package-question.vue", () => { // Assert expect(wrapper.vm.selectedPackageName).toBe("TierThree"); }); + it("should select default package if promos are added", async () => { + //Arrange + mockProps.activePromos != null; + const wrapper = setupMocks({ + mountOptionsMockData: { + store: { + getters: { + order: { + damage: { + isRepair: false, + glassToReplace: [{ glassLocation: "Windshield" }], + }, + }, + lineItems: { + vaps: [], + }, + hasAnyNonWindshieldGlassParts: false, + payment: { + isInsurance: false, + }, + }, + }, + }, + }); + + //Act + wrapper.setProps({ + activePromos: [ + { + discountedLineItemIds: [ + { + 0: "428ec73c-38e4-4e14-8703-a987b0391898", + 1: "79db94d7-163c-4408-a1ec-f83e58c11992", + }, + ], + partType: "PROMO_DISCOUNT", + promoCode: "1WIPER0", + partNumber: "WIPER DISCOUNT", + laborAmount: 0, + sellingPrice: -10, + kitPrice: 0, + salesTax: null, + }, + ], + }); + const selectDefaultPackageMock = jest.spyOn(wrapper.vm, "selectDefaultPackage"); + await nextTick(); + + //Assert + expect(selectDefaultPackageMock).toHaveBeenCalled(); + }); }); describe("service-package-question.vue, matching business rules for package display", () => { // mock scenarios in figma: 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 28727f155..6b84f3557 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -63,6 +63,9 @@ export default { this.selectDefaultPackage(); } }, + activePromos() { + this.selectDefaultPackage(); + }, selectedPackageName(newValue) { const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue); this.$emit("vapsItemsSelected", VapsProductsInSelectedPackage); From 9f527ce18d211bb3348eda88b615a353d00d8ee3 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Fri, 9 Feb 2024 12:00:00 -0500 Subject: [PATCH 20/54] CSR-1952: rearrange promo link and promos applied into cart --- src/fmg-components/cart/cart.vue | 182 +++++++++++------- src/layouts/payment-method/payment-method.vue | 10 +- 2 files changed, 113 insertions(+), 79 deletions(-) diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index 65701db71..59a5c8646 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -13,78 +13,94 @@ {{ getFormattedAmount("", amountDue) }}
-
-
- - - {{ getFormattedAmount("", packagePrice) }} - -
+
+
+
+ + + {{ getFormattedAmount("", packagePrice) }} + +
- -
- {{ cartItem.name }} - - - -
+ +
+ <{{ cartItem.name }}> + + + +
- -
- {{ cartItem.name }} - - - - {{ recycleFeeCartItem.name }} - - {{ getFormattedAmount(cartItem.category, cartItem.subTotal) }} -
+ +
+ {{ cartItem.name }} + + + + {{ recycleFeeCartItem.name }} + + {{ getFormattedAmount(cartItem.category, cartItem.subTotal) }} +
- -
- {{ subtotalText }}{{ getFormattedAmount("", subTotal) }} -
-
- {{ salesTaxText }}{{ getFormattedAmount("", salesTax) }} -
-
- {{ amountPaidText }}{{ getFormattedAmount("", amountPaid) }} -
-
- {{ amountDueText }}{{ getFormattedAmount("", amountDue) }} + +
+ {{ subtotalText }}{{ getFormattedAmount("", subTotal) }} +
+
+ {{ salesTaxText }}{{ getFormattedAmount("", salesTax) }} +
+
+ {{ amountPaidText }}{{ getFormattedAmount("", amountPaid) }} +
+
+ {{ amountDueText }}{{ getFormattedAmount("", amountDue) }} +
+
+
+ Promo code <{{ promoCode }}> applied +
@@ -96,6 +112,7 @@ import textLink from "@/ux-components/text-link/text-link"; import textBlock from "@/digital-components/text-block/text-block"; import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal"; +import promoModalQuestion from "@/layouts/payment-method/promo-modal-question/promo-modal-question"; // Mixins import baseMixin from "@/mixins/base-mixin.js"; @@ -198,6 +215,12 @@ export default { this.$emit("update:modelValue", this.lineItems); }, + getPromoCodeList() { + if (this.$refs["promoModalQuestion"]) { + return this.$refs["promoModalQuestion"].getPromoCodeList(); + } + return []; + }, }, computed: { screenReaderTotalAmountDueText() { @@ -796,16 +819,23 @@ export default { }, deep: true, }, + lineItems: { + handler(newValue) { + this.$emit("update:modelValue", this.lineItems); + }, + deep: true, + }, }, components: { textBlock, textLink, contentGroupModal, + promoModalQuestion, }, }; -