diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 9adfc0613..b2c7b4821 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -25,7 +25,7 @@ const endpoints = { method: "GET", }, GetDamageOptions: { - url: "/parts/api/v1/parts/damage-options", + url: "/parts/api/v2/parts/damage-options", method: "GET", }, LookupVehicleByYmms: { @@ -141,7 +141,7 @@ const endpoints = { method: "POST", }, ValidateZip: { - url: "/location/api/v1/location/zip", + url: "/location/api/v2/location/zip", method: "GET", }, PriceOrderItems: { diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index 9a6f55576..faa28376d 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -962,7 +962,8 @@ export default { return this.supportingItems.find( (lineItem) => lineItem.partType == partTypeStrings.MOBILE_FEE && - lineItem.partNumber == partNumberStrings.MOBILE_STATIC_RECAL_FEE + (lineItem.partNumber == partNumberStrings.MOBILE_STATIC_RECAL_FEE || + lineItem.partNumber == partNumberStrings.MOBILE_DUAL_RECAL_FEE) ); }, msrFeeCartItem() { diff --git a/src/helpers/damage-helper.js b/src/helpers/damage-helper.js index 1763ffbea..5c7a2de7c 100644 --- a/src/helpers/damage-helper.js +++ b/src/helpers/damage-helper.js @@ -103,7 +103,7 @@ export function getSideDoorGlassString(glassLocation, glassName) { export function getDamageInfoWordingText(damageInfo) { const glassTextArray = []; - damageInfo.glassToReplace.forEach((item) => { + damageInfo.glassToReplace?.forEach((item) => { let string = ""; if (item.glassLocation === glassLocations.WINDSHIELD) { string = item.glassLocation; diff --git a/src/helpers/pricing-helper.js b/src/helpers/pricing-helper.js index 9564b5c1f..fff87d82f 100644 --- a/src/helpers/pricing-helper.js +++ b/src/helpers/pricing-helper.js @@ -108,7 +108,9 @@ export async function getPricingByDayPartWithPrice(pageNameToLog) { export function getMSRFeePartPrice(supportingItems, includeTax) { let msrFeePrice = 0; const msrFeeLineItem = supportingItems?.find( - (lineItem) => lineItem.partNumber === partNumberStrings.MOBILE_STATIC_RECAL_FEE + (lineItem) => + lineItem.partNumber === partNumberStrings.MOBILE_STATIC_RECAL_FEE || + lineItem.partNumber === partNumberStrings.MOBILE_DUAL_RECAL_FEE ); if (msrFeeLineItem) { msrFeePrice = baseMixin?.methods?.getTotalPriceOfAllLineItemsAndChildParts( diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index 081be8def..a7e1f6bca 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -421,6 +421,7 @@ export default { state: resultMap.serviceZipValidationResponse.state, zipCode: this.serviceZipCode, zipCodeCtu: resultMap.serviceZipValidationResponse.zipCodeCtu, + providerNumber: resultMap.serviceZipValidationResponse.providerNumber, }, false ); diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index c4f5df92c..659c8bdc1 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -73,6 +73,8 @@ export default { zipCode: store.getters.externalParameterServiceZip.zipCode, state: null, zipCodeCtu: null, + providerNumber: + store.getters.externalParameterServiceZip.providerNumber, }, false ); diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index a1477a664..730d6b4f2 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -360,6 +360,7 @@ export default { state: resultMap.serviceZipValidationResponse.state, zipCode: this.serviceZipCode, zipCodeCtu: resultMap.serviceZipValidationResponse.zipCodeCtu, + providerNumber: resultMap.serviceZipValidationResponse.providerNumber, }, false ); diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index a7f4900de..268f7356c 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -73,6 +73,8 @@ export default { zipCode: store.getters.externalParameterServiceZip.zipCode, state: null, zipCodeCtu: null, + providerNumber: + store.getters.externalParameterServiceZip.providerNumber, }, false ); diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index 958a38095..800fed21d 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -75,6 +75,8 @@ export default { zipCode: store.getters.externalParameterServiceZip.zipCode, state: serviceState ?? null, zipCodeCtu: serviceZipCtu ?? null, + providerNumber: + store.getters.externalParameterServiceZip.providerNumber, }, false ); diff --git a/src/layouts/payment-adyen/payment-adyen.vue b/src/layouts/payment-adyen/payment-adyen.vue index 5b3a663ea..fc3ad668d 100644 --- a/src/layouts/payment-adyen/payment-adyen.vue +++ b/src/layouts/payment-adyen/payment-adyen.vue @@ -35,6 +35,7 @@ :insuranceCompanyName="insuranceCompanyName" :showInsuranceCoverageAs="showInsuranceCoverageAs" :isMSRFeeApplicable="isMSRFeeApplicable" + :IsMSRFeeCoveredByInsurance="isMSRFeeCoveredByInsurance" :isItac="isItac" :isNoComp="isNoComp" :isCollapsible="false" /> @@ -77,6 +78,7 @@ import { createAdyenCheckout } from "@/helpers/adyen-helper"; import { Dropin } from "@adyen/adyen-web/auto"; import { applicationConfig } from "@/constants/application-config"; import { paymentMethods } from "@/constants/payment-method-constants"; +import analyticsMixin from "@/mixins/analytics-mixin"; import "@adyen/adyen-web/styles/adyen.css"; import { mapAdyenToFmgPaymentMethod, mapFmgToAdyenPaymentMethod } from "../../helpers/adyen-helper"; @@ -133,6 +135,25 @@ export default { }, methods: { + async initializeAdyenWithErrorHandling() { + try { + await this.initializeAdyen(); + } catch (error) { + console.error("Failed to initialize Adyen payment:", error); + + const errorJson = JSON.stringify(error, Object.getOwnPropertyNames(Object(error))); + analyticsMixin.methods.pushFmgSessionData(errorJson); + await global.$logger.logError(errorJson); + + this.$router.navigateWithoutSaving( + this.navigationScenarios.PIA_ERROR, + this.pageName + ); + + return; + } + }, + async backButtonAction() { // Stub, for navigating back via nav-bar. this.$router.navigateWithoutSaving( @@ -203,6 +224,12 @@ export default { }, onError: (error, component) => { console.log(`Error from Adyen`); + const errorJson = JSON.stringify( + error, + Object.getOwnPropertyNames(Object(error)) + ); + analyticsMixin.methods.pushFmgSessionData(errorJson); + this.handleError(error); }, }, @@ -371,7 +398,12 @@ export default { await global.$logger.logError(stringToLog); - this.hasPaymentFailureError = true; + this.$router.navigateWithoutSaving( + this.navigationScenarios.PIA_ERROR, + this.pageName + ); + + return; } this.dropinComponent?.update(); @@ -560,13 +592,16 @@ export default { isMSRFeeApplicable() { return this.$store.getters.order.isMSRFeeApplicable; }, + isMSRFeeCoveredByInsurance() { + return this.$store.getters.order.isMSRFeeCoveredByInsurance; + }, lineItems() { return deepClone(this.$store.getters.lineItems); }, }, mounted() { - this.initializeAdyen(); + this.initializeAdyenWithErrorHandling(); }, components: { diff --git a/src/layouts/return-user/return-user.vue b/src/layouts/return-user/return-user.vue index ad307080d..6ce0b2528 100644 --- a/src/layouts/return-user/return-user.vue +++ b/src/layouts/return-user/return-user.vue @@ -47,6 +47,7 @@ import { Form } from "vee-validate"; import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; import { storeActions } from "@/constants/store-actions"; +import baseMixin from "@/mixins/base-mixin"; export default { name: "return-user", @@ -74,6 +75,13 @@ export default { startOverImage: null, }; }, + mounted() { + // The global baseMixin.mounted() skips hiding the loading modal when + // external-parameter state is active, but those parameters have no + // consumer on this interstitial. Clear that state and ensure the loader + // is hidden so the user can never get stuck behind it on this page. + baseMixin.methods.ResetExternalParamsAndHideModal(); + }, methods: { arePagePrerequisitesValid() { return getFunnelCookie() !== null; diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index c483c90df..002440ec3 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -706,10 +706,16 @@ export default { isMobileStaticRecalibrationApplicable() { return ( this.displayMSR && - this.mobileFeePart?.partNumber == partNumberStrings.MOBILE_STATIC_RECAL_FEE && + this.isMSRFeePartNumber && (this.enableMSRSplitPay || this.isCashItacNoComp || this.mobileFeePart?.isInsurable) ); }, + isMSRFeePartNumber() { + return ( + this.mobileFeePart?.partNumber === partNumberStrings.MOBILE_STATIC_RECAL_FEE || + this.mobileFeePart?.partNumber === partNumberStrings.MOBILE_DUAL_RECAL_FEE + ); + }, displayMSR() { return ( experimentMixin.methods @@ -1804,6 +1810,7 @@ export default { zipCode: newZipCode.zipCode, state: newZipCode.state, zipCodeCtu: newZipCode.zipCodeCtu, + providerNumber: newZipCode.providerNumber, }, false ); diff --git a/src/layouts/service-zip/service-zip.vue b/src/layouts/service-zip/service-zip.vue index c82a0a0e3..47538cbd9 100644 --- a/src/layouts/service-zip/service-zip.vue +++ b/src/layouts/service-zip/service-zip.vue @@ -135,6 +135,8 @@ export default { zipCode: store.getters.externalParameterServiceZip.zipCode, state: null, zipCodeCtu: null, + providerNumber: + store.getters.externalParameterServiceZip.providerNumber, }, false ); @@ -246,6 +248,7 @@ export default { zipCode: this.serviceZipCode, state: zipCodeData.state, zipCodeCtu: zipCodeData.zipCodeCtu, + providerNumber: zipCodeData.providerNumber, }, false ); diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index e68598bd4..487c3ee05 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -184,6 +184,8 @@ export default { zipCode: store.getters.externalParameterServiceZip.zipCode, state: null, zipCodeCtu: null, + providerNumber: + store.getters.externalParameterServiceZip.providerNumber, }, false ); diff --git a/src/layouts/vehicle/vehicle.vue b/src/layouts/vehicle/vehicle.vue index 5c80694bf..b6ddc1bb9 100644 --- a/src/layouts/vehicle/vehicle.vue +++ b/src/layouts/vehicle/vehicle.vue @@ -525,6 +525,7 @@ export default { zipCode: this.serviceZipCode, state: zipCodeData.state, zipCodeCtu: zipCodeData.zipCodeCtu, + providerNumber: zipCodeData.providerNumber, }, false ); diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index ae80f670f..74bc0e11e 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -380,6 +380,7 @@ export default { state: resultMap.zipCodeData.state, zipCode: this.serviceZipCode, zipCodeCtu: resultMap.zipCodeData.zipCodeCtu, + providerNumber: resultMap.zipCodeData.providerNumber, }, false ); @@ -401,6 +402,7 @@ export default { state: zipCodeData.state, zipCode: this.serviceZipCode, zipCodeCtu: zipCodeData.zipCodeCtu, + providerNumber: zipCodeData.providerNumber, }, false ); diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 3ab575f58..1ea812c49 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -160,12 +160,16 @@ export default { // and aws FireHose stream, DigitalConsumer-Session-Firehose, to push data to an // S3 bucket, safelite-dev-digitalconsumer-session-data-us-east-2/1. // This bucket data is then picked up by snowflake for analytics use. - async pushFmgSessionData() { + async pushFmgSessionData(errorJson = null) { var currentPageName = getPageNameFromRouter(true); if (!currentPageName) { return; } + if (errorJson) { + currentPageName += ` ERROR: ${errorJson}`; + } + const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder(); const submittedOrder = baseMixin.methods.getSubmittedOrder(); const order = hasSubmittedOrder ? submittedOrder : store.getters.order; @@ -209,6 +213,7 @@ export default { var appointment = `${order?.schedule?.date ?? ""} ${order?.schedule?.startTime ?? ""}`; var sessionData = {}; + sessionData.currentPage = currentPageName; sessionData.sid = getSessionIdValue(); sessionData.deviceId = getDeviceIdValue(); @@ -931,6 +936,11 @@ function getPageNameFromRouter(useDefaultUrl = false) { router.currentRoute.value && router.currentRoute.value.name ) { + const query = router.currentRoute.value.query; + if (query && Object.keys(query).length > 0 && useDefaultUrl === true) { + const queryString = new URLSearchParams(query).toString(); + return `${router.currentRoute.value.name}?${queryString}`; + } return router.currentRoute.value.name; } diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index 4ca139275..24cb7949b 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -82,6 +82,7 @@ export default { isServiceable: serviceZipValidationResponse.data.isServiceable, state: serviceZipValidationResponse.data.state, zipCodeCtu: serviceZipValidationResponse.data.zipCodeCtu, + providerNumber: serviceZipValidationResponse.data.providerNumber, }; }, getTierOnePackagePrice(lineItems) { diff --git a/src/router/methods/helpers/initialize-from-querystrings.js b/src/router/methods/helpers/initialize-from-querystrings.js index 4d342cdc0..95cbad6fc 100644 --- a/src/router/methods/helpers/initialize-from-querystrings.js +++ b/src/router/methods/helpers/initialize-from-querystrings.js @@ -147,6 +147,7 @@ function resetStoreForExternalParameter() { state: null, zipCode: null, zipCodeCtu: null, + providerNumber: null, }); store.dispatch(storeActions.SAVE_EMAIL, null); store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); diff --git a/src/router/methods/route-logic/vehicle.js b/src/router/methods/route-logic/vehicle.js index e7ff41fc0..7221ef275 100644 --- a/src/router/methods/route-logic/vehicle.js +++ b/src/router/methods/route-logic/vehicle.js @@ -30,6 +30,7 @@ export async function vehicleBeforeEnter(to, from) { zipCode: newZipFromQuerystring, state: zipData.state, zipCodeCtu: zipData.zipCodeCtu, + providerNumber: zipData.providerNumber, }); } } diff --git a/src/store/index.js b/src/store/index.js index a58200a96..32347624b 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -465,6 +465,7 @@ export const mutations = { state.order.serviceLocation.state = serviceZipInfo.state; state.order.serviceLocation.zipCode = serviceZipInfo.zipCode; state.order.serviceLocation.zipCodeCtu = serviceZipInfo.zipCodeCtu; + state.order.serviceLocation.providerNumber = serviceZipInfo.providerNumber; }, updateServiceLocation(state, serviceLocationInfo) { state.order.serviceLocation.address = serviceLocationInfo.address; @@ -3471,7 +3472,8 @@ export const actions = { { payload: { parentAccountNumber = context.getters.order.payment.parentAccountNumber, - providerNumber = context.getters.order.serviceLocation.zipCodeCtu, + providerNumber = context.getters.order.serviceLocation.providerNumber || + context.getters.order.serviceLocation.zipCodeCtu, isItac = context.getters.order.policy.isItac, }, pageNameToLog,