From 4056dcf8d1f6cb659e23b6f3ab211037ed8759c2 Mon Sep 17 00:00:00 2001 From: Josh Dassinger Date: Fri, 20 Feb 2026 14:21:41 -0600 Subject: [PATCH] INSR-8549 Fixed Zipcode 99546 causing all sorts of issues in NextGen --- src/helpers/service-location-helper.js | 57 ++++++-- src/layouts/schedule-page/schedule-page.vue | 46 ++---- .../service-location/service-location.spec.js | 2 +- .../service-location/service-location.vue | 83 ++++------- src/layouts/welcome-page/welcome-page.vue | 1 - src/store/index.js | 138 ++++++++++-------- 6 files changed, 159 insertions(+), 168 deletions(-) diff --git a/src/helpers/service-location-helper.js b/src/helpers/service-location-helper.js index 7e10ccd2..8e4bb332 100644 --- a/src/helpers/service-location-helper.js +++ b/src/helpers/service-location-helper.js @@ -1,4 +1,6 @@ import { useMainStore } from '@/store'; +import { AppointmentTypeStrings } from '@/constants/schedule-constants'; +import settleAllPromises from '@/helpers/layout-helper'; function processZipCodeResults(request) { return request.then((serviceZipValidationResponse) => ({ @@ -29,7 +31,7 @@ export async function getPricedMobileFeePart(serviceZipCode) { // Get the Mobile Fee Part const mobileFeePart = await useMainStore().getMobileFeePart(); - if (mobileFeePart.data == null || mobileFeePart.data === '') { + if (mobileFeePart?.data == null || mobileFeePart.data === '') { return Promise.resolve(null); } @@ -40,17 +42,6 @@ export async function getPricedMobileFeePart(serviceZipCode) { return Promise.resolve(pricingResults[0]); } -export async function getServiceabilityDetails(serviceZipCode, lineItems) { - const serviceabilityDetails = await useMainStore().getServiceabilityDetails( - { - serviceZipCode, - lineItems - }, - false - ); - return Promise.resolve(serviceabilityDetails); -} - export async function getAvailabilityRating( startDate, endDate, @@ -69,3 +60,45 @@ export async function getAvailabilityRating( return Promise.resolve(shopStatus); } + +export function getProviderData() { + const mainStore = useMainStore(); + const storeServiceLocation = mainStore.order.serviceLocation; + const storeSelectedAppointmentType = storeServiceLocation?.appointmentType; + const isMobileAppointment = storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE + || storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP; + const storeSelectedProvider = storeServiceLocation?.provider; + const serviceZipCode = storeServiceLocation?.zipCode || mainStore.order.customer.address.zipCode; + + return { storeServiceLocation, isMobileAppointment, storeSelectedProvider, serviceZipCode } +} + +export async function onProviderChanged() { + const { isMobileAppointment, storeSelectedProvider, serviceZipCode } = getProviderData(); + if (!storeSelectedProvider) { + return; + } + + const mainStore = useMainStore(); + + await mainStore.getBillToInfo(storeSelectedProvider.providerNumber); + const promiseResultMap = [ + { + resultKey: 'glassFees', + promise: mainStore.getGlassFees() + .then(async (glassFees) => await mainStore.getCombinedQuote(glassFees)) + .then(async (quotedGlassFees) => mainStore.updateGlassFees(quotedGlassFees)) + }, + ]; + + if (isMobileAppointment && (this.mainStore.isNoComp || this.mainStore.isITAC)) { + promiseResultMap.push({ + resultKey: 'priceMobileFee', + promise: getPricedMobileFeePart(serviceZipCode).then(mobileFee => mainStore.updateMobileFee(mobileFee)) + }); + } else { + mainStore.updateMobileFee(null); + } + + await settleAllPromises(promiseResultMap); +} \ No newline at end of file diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index 28b73548..ed488446 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -89,9 +89,9 @@ import { import settleAllPromises from '@/helpers/layout-helper'; import showIssLoadingModal from '@/helpers/loading-modal-helper.js'; import { - getPricedMobileFeePart, - getServiceabilityDetails, - getZipCodeData + getProviderData, + getZipCodeData, + onProviderChanged } from '@/helpers/service-location-helper'; import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; @@ -225,16 +225,9 @@ export default { async beforeRouteEnter(to, from, next) { // Call APIs const cmsContentPromise = fetchCmsContentForPage(to.query.issPage); - const storeServiceLocation = useMainStore().order.serviceLocation; - const storeSelectedAppointmentType = storeServiceLocation?.appointmentType; - const isMobileAppointment = storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE - || storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP; - const storeSelectedProvider = storeServiceLocation?.provider; - const serviceZipCode = storeServiceLocation?.zipCode || useMainStore().order.customer.address.zipCode; + const { isMobileAppointment, storeSelectedProvider, serviceZipCode } = getProviderData(); const zipCodeData = getZipCodeData(serviceZipCode); - const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode); - const serviceabilityDetailsPromise = getServiceabilityDetails(serviceZipCode); - const getGlassFeesPromise = useMainStore().getGlassFees(); + const serviceabilityDetailsPromise = useMainStore().getServiceabilityDetails(serviceZipCode); const providersPromise = useMainStore().getSafeliteProviders(serviceZipCode, 150); const premiumFeePromise = useMainStore().getMobilePremiumFee(); @@ -251,14 +244,6 @@ export default { resultKey: 'cmsContent', promise: cmsContentPromise }, - { - resultKey: 'mobileFeePart', - promise: mobileFeePartPromise - }, - { - resultKey: 'glassFees', - promise: getGlassFeesPromise - }, { resultKey: 'serviceabilityDetails', promise: serviceabilityDetailsPromise @@ -271,6 +256,10 @@ export default { resultKey: 'providers', promise: providersPromise }, + { + resultKey: 'providerChanged', + promise: onProviderChanged() + }, { resultKey: 'premiumFeeWithPrice', promise: premiumFeeWithPricePromise @@ -332,7 +321,6 @@ export default { inShopDatesData: [], isMobileView: false, mobileDatesData: [], - mobileFeePart: null, mobilePremiumAppointmentFee: null, mobileProviderNumber: null, selectableDatesData: [], @@ -672,17 +660,10 @@ export default { async providerChangedFromServiceLocation(newProvider) { this.selectedProvider = newProvider?.provider; if (newProvider?.refreshDatePicker && newProvider.provider) { - this.mainStore.updateServiceLocationProvider(newProvider.provider); - showIssLoadingModal(true); - await this.mainStore.getBillToInfo(newProvider.provider?.providerNumber) - .then(() => { - this.refreshDatePicker(); - }) - .catch(() => { - console.warn('Error fetching bill to info...'); - showIssLoadingModal(false); - }); + this.mainStore.updateServiceLocation(newProvider); + await onProviderChanged(); + await this.refreshDatePicker(); } }, async refreshDatePicker() { @@ -713,8 +694,7 @@ export default { appointmentTypeToUse = AppointmentTypeStrings.DROP_OFF; } - // Save service location then save schedule then navigate forward - await this.$refs.serviceLocation.forwardButtonAction(appointmentTypeToUse); + this.mainStore.updateAppointmentType(appointmentTypeToUse); this.mainStore.saveSchedule(this.selectedTimeSlotInfo.timeSlot); this.$router.navigate( this.navigationScenarios.CLICKED_FORWARD, diff --git a/src/layouts/schedule-page/service-location/service-location.spec.js b/src/layouts/schedule-page/service-location/service-location.spec.js index 003ae457..7b1b4294 100644 --- a/src/layouts/schedule-page/service-location/service-location.spec.js +++ b/src/layouts/schedule-page/service-location/service-location.spec.js @@ -86,7 +86,6 @@ const mockProviders = () => Promise.resolve([ jest.mock( '@/helpers/service-location-helper', () => ({ - getServiceabilityDetails: jest.fn((mockServiceZipCode) => mockGetServiceabilityDetails(mockServiceZipCode)), getZipCodeData: jest.fn((mockServiceZipCode) => mockZipcodeData(mockServiceZipCode)), getMobileZipCodeData: jest.fn((mockServiceZipCode) => mockZipcodeData(mockServiceZipCode)) }) @@ -147,6 +146,7 @@ function setupMocks({ appointmentType = AppointmentTypeStrings.IN_SHOP }) { } })]; useMainStore().getSafeliteProviders = jest.fn().mockImplementation(() => mockProviders()); + useMainStore().getServiceabilityDetails = jest.fn((mockServiceZipCode) => mockGetServiceabilityDetails(mockServiceZipCode)); const wrapper = mount(serviceLocation, mountOptions); wrapper.vm.$router.navigateWithSpinner = jest.fn(); diff --git a/src/layouts/schedule-page/service-location/service-location.vue b/src/layouts/schedule-page/service-location/service-location.vue index bca1ba72..5b43a165 100644 --- a/src/layouts/schedule-page/service-location/service-location.vue +++ b/src/layouts/schedule-page/service-location/service-location.vue @@ -129,7 +129,6 @@ import errorMessages from '@/constants/error-messages'; import { useMainStore } from '@/store'; import showIssLoadingModal from '@/helpers/loading-modal-helper.js'; import { - getServiceabilityDetails, getZipCodeData, getMobileZipCodeData } from '@/helpers/service-location-helper'; @@ -183,7 +182,6 @@ export default { isRecalibrationServiceableMobile: null, selectedAppointmentType: this.getSelectedAppointmentType(), selectedProvider: this.getSelectedProvider(), - mobileFeePart: null, mobileProviderNumber: null, zipContainsMilitaryBase: false, zipCodeCtu: null, @@ -233,8 +231,8 @@ export default { }, isInshop() { return ( - this.selectedAppointmentType === 'Inshop' - || this.selectedAppointmentType === 'Dropoff' + this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP + || this.selectedAppointmentType === AppointmentTypeStrings.DROP_OFF ); }, isMobile() { @@ -317,7 +315,7 @@ export default { }, selectedAppointmentType(newValue, oldValue) { if (this.isInshop && this.selectedProvider && this.availabilityRating === null) { - const appointmenTypeServiceLocationObj = { + const appointmentTypeServiceLocationObj = { appointmentType: newValue, mobileProviderNumber: null, provider: this.selectedProvider, @@ -326,9 +324,9 @@ export default { zipCode: this.zipCode, zipCodeCtu: this.zipCodeCtu }; - this.$emit('appointment-type-changed', appointmenTypeServiceLocationObj); + this.$emit('appointment-type-changed', appointmentTypeServiceLocationObj); } else { - const appointmenTypeServiceLocationObj = { + const appointmentTypeServiceLocationObj = { appointmentType: newValue, mobileProviderNumber: this.mobileProviderNumber, provider: null, @@ -337,20 +335,31 @@ export default { zipCode: this.zipCode, zipCodeCtu: this.zipCodeCtu }; - this.$emit('appointment-type-changed', appointmenTypeServiceLocationObj); + this.$emit('appointment-type-changed', appointmentTypeServiceLocationObj); } }, selectedProvider(newProvider, oldProvider) { - if (newProvider?.providerNumber !== oldProvider?.providerNumber || this.availabilityRating === null) { + if (newProvider?.providerNumber !== oldProvider?.providerNumber) { const appointmentIsInshop = this.isInshop; const returnedProvider = { - provider: newProvider, - refreshDatePicker: appointmentIsInshop && oldProvider?.providerNumber !== null + refreshDatePicker: appointmentIsInshop && oldProvider?.providerNumber !== null, + state: this.state, + zipCode: this.zipCode, + zipCodeCtu: this.zipCodeCtu, + appointmentType: this.selectedAppointmentType, + provider: !this.isMobile ? newProvider : { + providerNumber: this.mobileProviderNumber, + address: { + streetAddress: null, + city: null, + state: null, + zipCode: null, + zipCodeCtu: null + } + } }; - if (newProvider?.providerNumber !== oldProvider?.providerNumber) { - this.$emit('provider-changed', returnedProvider); - } + this.$emit('provider-changed', returnedProvider); } } }, @@ -360,34 +369,6 @@ export default { await this.setData(initialData); this.initializingData = false; }, - async forwardButtonAction(appointmentType) { - let provider = this.selectedProvider; - this.mainStore.updateMobileFee(null); - if (this.isMobile) { - if (this.mainStore.isNoComp || this.mainStore.isITAC) { - this.mainStore.updateMobileFee(this.mobileFeePart); - } - - provider = { - providerNumber: this.mobileProviderNumber, - address: { - streetAddress: null, - city: null, - state: null, - zipCode: null, - zipCodeCtu: null - } - }; - } - - this.mainStore.saveServiceLocation({ - state: this.state, - zipCode: this.zipCode, - zipCodeCtu: this.zipCodeCtu, - appointmentType: appointmentType || this.selectedAppointmentType, - provider - }); - }, openModalAction(modalName) { this.$refs[modalName].openModal(); }, @@ -427,7 +408,7 @@ export default { this.setCtuForMobile(zipCodeData.zipCodeCtu); this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase); - const serviceabilityDetailsPromise = getServiceabilityDetails(this.zipCode); + const serviceabilityDetailsPromise = this.mainStore.getServiceabilityDetails(this.zipCode); await serviceabilityDetailsPromise.then((result) => { const details = result.data; if (details) { @@ -465,10 +446,6 @@ export default { this.setServiceabilityDetails(initialData.serviceabilityDetails); } - if (initialData.mobileFeePart) { - this.mobileFeePart = initialData.mobileFeePart; - } - if (initialData.providers) { this.setMobileProviderNumber(initialData.providers.mobileProviderNumber); let foundMatch = false; @@ -485,22 +462,12 @@ export default { this.selectedProvider = null; } } - - if (initialData.glassFees) { - useMainStore().getCombinedQuote(initialData.glassFees) - .then((combinedQuote) => { - this.setGlassFeeItems(combinedQuote); - }); - } }, setContainsMilitaryBase(val) { if (this.zipContainsMilitaryBase !== val) { this.zipContainsMilitaryBase = val; } }, - setGlassFeeItems(newGlassFeeItems) { - this.mainStore.updateGlassFees(newGlassFeeItems); - }, setMobileProviderNumber(providerNumber) { this.mobileProviderNumber = providerNumber; }, @@ -531,7 +498,7 @@ export default { this.setCtuForMobile(zipCodeData.zipCodeCtu); this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase); - const serviceabilityDetailsPromise = getServiceabilityDetails(this.mobileZipCode); + const serviceabilityDetailsPromise = this.mainStore.getServiceabilityDetails(this.mobileZipCode); await serviceabilityDetailsPromise.then((result) => { const details = result.data; if (details) { diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index 15e96929..72ca60b6 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -319,7 +319,6 @@ export default { } const promises = [ - // Suppress error from API call we can try again later in the flow this.mainStore.getBillToInfo() ]; // Skip duplicate check if loaded from cookie or already visited duplicate check page. diff --git a/src/store/index.js b/src/store/index.js index d947829b..710e4c6b 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -873,6 +873,10 @@ export const useMainStore = defineStore({ }, getMobileTimeSlots(startDate, endDate, zipCodeOverride = null) { const { order } = this; + if (!this.billToAccountNumber) { + return null; + } + const { vehicle } = this.order; let lineItems = [ ...(order.lineItems.supportingItems ?? []), @@ -928,6 +932,9 @@ export const useMainStore = defineStore({ }, getShopTimeSlots(startDate, endDate, shopAppointmentType, providerNumber) { const { order } = this; + if (!this.billToAccountNumber || !providerNumber) { + return null; + } const { vehicle } = this.order; let lineItems = [ @@ -1125,6 +1132,10 @@ export const useMainStore = defineStore({ const providerToUse = provider?.providerNumber ?? defaultProviderNumber; const partNumberListQueryString = getPartNumbersListForQueryString(glassParts, 'PartNumbers'); + if (!this.billToAccountNumber || !providerToUse) { + return null + } + const params = new URLSearchParams({ serviceType: damageType, facilityType, @@ -1242,62 +1253,74 @@ export const useMainStore = defineStore({ }, async getCombinedQuote(availableLineItems) { - if (availableLineItems && availableLineItems.length > 0) { - const { vehicle, serviceLocation, policy, eon, referralNumber, referralDate, referralSequenceNumber, lineItems } = this.order; - - const availableLineItemsFiltered = availableLineItems.filter((lineItem) => !!(lineItem.partNumber)); - - const lineItemsWithOnlyPartNumbers = availableLineItemsFiltered.map((lineItem) => ({ partNumber: lineItem.partNumber })); - - const payload = { - ParentAccountNumber: this.order.parentAccountNumber, - BillToAccountNumber: this.billToAccountNumber, - ProviderNumber: this.providerNumber, - CarId: vehicle.carId, - Make: vehicle.make, - Model: vehicle.model, - Year: vehicle.year, - EON: eon, - ZipCode: policy.policyZipCode, - State: this.order.customer.address.state, - ReferralNumber: referralNumber, - ReferralDate: referralDate, - ReferralSequenceNumber: referralSequenceNumber, - ServiceZipCode: serviceLocation.zipCode, - IsReplacement: !this.isRepair, - ServerData: lineItems.serverData, - LineItems: lineItemsWithOnlyPartNumbers, - FeatureToggles: getFeatureTogglesPayloadObject(this.experimentSettings) - }; - - const response = await globalMethods - .callHttpClient({ - method: endpoints.GetCombinedQuote.method, - endpoint: endpoints.GetCombinedQuote.url, - payload - }) - .catch((error) => { - console.error(error); - return []; - }); - - const { lineItems: pricedLinedItems, serverData } = response.data; - - if (serverData) { - this.order.lineItems.serverData = serverData; - } - - if (pricedLinedItems) { - return addPricesToLineItems(availableLineItems, pricedLinedItems); - } - return availableLineItems; + if (!availableLineItems || availableLineItems.length === 0) { + return []; } - return []; + const { + vehicle, + serviceLocation, + policy, + eon, + referralNumber, + referralDate, + referralSequenceNumber, + lineItems + } = this.order; + + const availableLineItemsFiltered = availableLineItems.filter((lineItem) => !!(lineItem.partNumber)); + + const lineItemsWithOnlyPartNumbers = availableLineItemsFiltered.map((lineItem) => ({ partNumber: lineItem.partNumber })); + + const payload = { + ParentAccountNumber: this.order.parentAccountNumber, + BillToAccountNumber: this.billToAccountNumber, + ProviderNumber: this.providerNumber, + CarId: vehicle.carId, + Make: vehicle.make, + Model: vehicle.model, + Year: vehicle.year, + EON: eon, + ZipCode: policy.policyZipCode, + State: this.order.customer.address.state, + ReferralNumber: referralNumber, + ReferralDate: referralDate, + ReferralSequenceNumber: referralSequenceNumber, + ServiceZipCode: serviceLocation.zipCode, + IsReplacement: !this.isRepair, + ServerData: lineItems.serverData, + LineItems: lineItemsWithOnlyPartNumbers, + FeatureToggles: getFeatureTogglesPayloadObject(this.experimentSettings) + }; + + const response = await globalMethods + .callHttpClient({ + method: endpoints.GetCombinedQuote.method, + endpoint: endpoints.GetCombinedQuote.url, + payload + }) + .catch((error) => { + console.error(error); + return []; + }); + + const { lineItems: pricedLinedItems, serverData } = response.data; + + if (serverData) { + this.order.lineItems.serverData = serverData; + } + + if (pricedLinedItems) { + return addPricesToLineItems(availableLineItems, pricedLinedItems); + } + return availableLineItems; }, getMobileFeePart() { const { vehicle, insuranceCoverage } = this.order; + if (!this.billToAccountNumber || !this.providerNumber) { + return null; + } const params = new URLSearchParams({ serviceType: this.damage.isRepair ? 'Repair' : 'Install', @@ -1836,19 +1859,8 @@ export const useMainStore = defineStore({ } this.order.serviceLocation.tpaSearchRadius = serviceLocationInfo.tpaSearchRadius; }, - updateServiceLocationProvider(providerInfo) { - this.order.serviceLocation.provider = { - providerNumber: providerInfo?.providerNumber, - address: { - streetAddress: providerInfo?.address?.streetAddress, - city: providerInfo?.address?.city, - state: providerInfo?.address?.state, - zipCode: providerInfo?.address?.zipCode, - zipCodeCtu: providerInfo?.address?.zipCodeCtu - }, - companyName: providerInfo?.companyName, - phoneNumber: providerInfo?.phoneNumber - }; + updateAppointmentType(appointmentType) { + this.order.serviceLocation.appointmentType = appointmentType; }, resetState() { Object.assign(this, getDefaultState());