From ea5836b3e42d21d6635708a8ceeff769cef42e52 Mon Sep 17 00:00:00 2001 From: Josh Dassinger Date: Thu, 19 Feb 2026 11:13:29 -0600 Subject: [PATCH] Address comments about policy / deductible / coverage calls failing should not bailout and just switch to no coverage IsVinAddressable API call failure now returns false Improved logging for cases Fixed Vehicle Style bailout when selecting select style value --- src/global-methods.js | 5 +- .../policy-vehicles/policy-vehicles.vue | 1 - .../vehicle-selection/vehicle-selection.vue | 22 +- src/main.js | 4 +- src/store/index.js | 267 +++++++++--------- src/store/store.spec.js | 26 +- 6 files changed, 169 insertions(+), 156 deletions(-) diff --git a/src/global-methods.js b/src/global-methods.js index 7a6fcf33..7f7ad72b 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -94,10 +94,11 @@ export default { } if (error.response.status !== 404) { - global.$logger.logError(`${method}: ${endpoint}: ${error.message}`, error.response); + const errorData = { method, url, payload, error }; + global.$logger.logError(`${method}: ${endpoint}`, errorData); if (bailoutOnError && global.bailoutOnAxiosError !== undefined) { - global.bailoutOnAxiosError({ method, url, payload, error }); + global.bailoutOnAxiosError(errorData); } } return reject(error.response); diff --git a/src/layouts/policy-vehicles/policy-vehicles.vue b/src/layouts/policy-vehicles/policy-vehicles.vue index c3b6c8ee..9cedd58d 100644 --- a/src/layouts/policy-vehicles/policy-vehicles.vue +++ b/src/layouts/policy-vehicles/policy-vehicles.vue @@ -214,7 +214,6 @@ export default { }); this.navigateForward(); } catch (e) { - debugger; if (e.isAxiosError && e.status === 404) { this.mainStore.resetVehicleState(); useMainStore().updateVehicle({ diff --git a/src/layouts/vehicle-selection/vehicle-selection.vue b/src/layouts/vehicle-selection/vehicle-selection.vue index 1cfb7f4d..e489fe0d 100644 --- a/src/layouts/vehicle-selection/vehicle-selection.vue +++ b/src/layouts/vehicle-selection/vehicle-selection.vue @@ -163,16 +163,18 @@ export default { } }, selectedStyle(value) { - this.resetAlert(); - this.mainStore.updateVehicleStyle(value); - this.mainStore.setVehicle( - this.selectedYear, - this.selectedMake, - this.selectedModel, - this.selectedStyle - ).then((result) => { - this.displayNoServiceAlert = !result.data.canSafeliteService; - }); + if (value) { + this.resetAlert(); + this.mainStore.updateVehicleStyle(value); + this.mainStore.setVehicle( + this.selectedYear, + this.selectedMake, + this.selectedModel, + this.selectedStyle + ).then((result) => { + this.displayNoServiceAlert = !result.data.canSafeliteService; + }); + } } }, mounted() { diff --git a/src/main.js b/src/main.js index 243335b9..440bcaca 100644 --- a/src/main.js +++ b/src/main.js @@ -48,7 +48,7 @@ function getPageName(vm) { // Vue Error Handling vueApp.config.errorHandler = (err, vm, info) => { const pageName = getPageName(vm); - global.$logger.logError(`Page Name - ${pageName} - ${info}: ${err.message}\n${err.stack}`); + global.$logger.logError(`[${pageName}] ${info}`, err); if (applicationConfig.BAILOUT_ON_APPLICATION_ERROR) { router.navigateBailout(bailoutMessage.applicationError(`[${pageName}] ${info}: ${err.message}\n${err.stack}`)); } @@ -56,7 +56,7 @@ vueApp.config.errorHandler = (err, vm, info) => { // Vue Router Error Handling router.onError((err) => { - global.$logger.logError(err.message, err.cause); + global.$logger.logError('Router Error:', err); if (applicationConfig.BAILOUT_ON_ROUTER_ERROR) { router.navigateBailout(bailoutMessage.routerError(`${err.message}\n${err.stack}`)); } diff --git a/src/store/index.js b/src/store/index.js index 862206e8..c36f5ae2 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -25,6 +25,7 @@ import { buildURLSearchParams, getPartNumbersListForQueryString } from '@/helper import { getTopLevelGlassPartsWithRecal } from '@/helpers/recal-helper'; import { getDateForSavedSessionTimeout } from '@/helpers/session-helper'; import issPageValues from '@/router/router-constants/issPage-values'; +import CoverageStatuses from '@/constants/coverage-statuses'; const storeId = 'main'; @@ -528,12 +529,16 @@ export const useMainStore = defineStore({ payload: {} }); }, - getIsVinbyAddressPermissible() { - return globalMethods.callHttpClient({ - method: endpoints.IsVinbyAddressPermissible.method, - endpoint: `${endpoints.IsVinbyAddressPermissible.url}?state=${this.order.customer.address.state}`, - payload: {} - }); + async getIsVinbyAddressPermissible() { + try { + return globalMethods.callHttpClient({ + method: endpoints.IsVinbyAddressPermissible.method, + endpoint: `${endpoints.IsVinbyAddressPermissible.url}?state=${this.order.customer.address.state}`, + payload: {} + }); + } catch (e) { + return false; + } }, async getCoveragePolicyInfo() { const { order, issConfig, applicationUser } = this; @@ -547,42 +552,47 @@ export const useMainStore = defineStore({ this.applicationUser.coverageAttempts += 1; console.log(`Coverage lookup attempt #${this.applicationUser.coverageAttempts}. Max attempts allowed: 10.`); - const response = await globalMethods.callHttpClient({ - method: endpoints.CoveragePolicyInfo.method, - endpoint: endpoints.CoveragePolicyInfo.url, - payload: { - accountNumber: order.parentAccountNumber?.toString(), - policyNumber: policy.policyNumber, - dateOfLoss: policy.dateOfLoss, - zipCode: policy.policyZipCode, - referralCorrelationId: order.referralCorrelationId + try { + const response = await globalMethods.callHttpClient({ + method: endpoints.CoveragePolicyInfo.method, + endpoint: endpoints.CoveragePolicyInfo.url, + payload: { + accountNumber: order.parentAccountNumber?.toString(), + policyNumber: policy.policyNumber, + dateOfLoss: policy.dateOfLoss, + zipCode: policy.policyZipCode, + referralCorrelationId: order.referralCorrelationId + }, + bailoutOnError: false + }); + + const responsePolicy = response?.data?.policies?.[0]; + if (responsePolicy) { + this.updateCoverageType(coverageType.Deductible); + const insured = responsePolicy.insureds?.[0]; + + // populate parent account number + if (response.data.accountNumber) { + order.parentAccountNumber = parseInt(response.data.accountNumber, 10); + } + + // populate policy holder details from policy lookup + order.customer.address.streetAddress = insured?.address; + order.customer.address.city = insured?.city; + order.customer.address.state = insured?.state; + order.customer.address.zipCode = insured?.zipCode?.toString(); + order.customer.firstName = insured?.firstName; + order.customer.lastName = insured?.lastName; + + // populate additional fields + order.policy.policyData = responsePolicy.policyData; + + // populate vehicles + order.policy.vehicles = responsePolicy.vehicles ?? []; + } else { + this.updateCoverageType(coverageType.NONE); } - }); - - const responsePolicy = response?.data?.policies?.[0]; - if (responsePolicy) { - this.updateCoverageType(coverageType.Deductible); - const insured = responsePolicy.insureds?.[0]; - - // populate parent account number - if (response.data.accountNumber) { - order.parentAccountNumber = parseInt(response.data.accountNumber, 10); - } - - // populate policy holder details from policy lookup - order.customer.address.streetAddress = insured?.address; - order.customer.address.city = insured?.city; - order.customer.address.state = insured?.state; - order.customer.address.zipCode = insured?.zipCode?.toString(); - order.customer.firstName = insured?.firstName; - order.customer.lastName = insured?.lastName; - - // populate additional fields - order.policy.policyData = responsePolicy.policyData; - - // populate vehicles - order.policy.vehicles = responsePolicy.vehicles ?? []; - } else { + } catch (e) { this.updateCoverageType(coverageType.NONE); } }, @@ -601,82 +611,81 @@ export const useMainStore = defineStore({ updateIsItacOptimized(isItacOptimized) { this.order.insuranceCoverage.isItacOptimized = isItacOptimized || false; }, - registerClaim() { + async registerClaim() { const nonNumberCharRegex = /[^0-9]/g; - const { order, isITAC } = this; - return new Promise((resolve, reject) => { - globalMethods.callHttpClient({ + const { isITAC } = this; + + try { + const response = await globalMethods.callHttpClient({ method: endpoints.RegisterClaim.method, endpoint: endpoints.RegisterClaim.url, payload: - { - referralCorrelationId: this.order.referralCorrelationId, - accountNumber: this.order.parentAccountNumber?.toString() ?? '', - policyData: this.order.policy.policyData, - isItac: isITAC, - insured: { - firstName: this.order.customer.firstName, - lastName: this.order.customer.lastName, - address: { - addressLine1: this.order.customer.address.streetAddress, - addressLine2: this.order.customer.address.streetAddress2, - city: this.order.customer.address.city, - state: this.order.customer.address.state, - zipCode: this.order.customer.address.zipCode, - country: 'US' // TODO set from store + { + referralCorrelationId: this.order.referralCorrelationId, + accountNumber: this.order.parentAccountNumber?.toString() ?? '', + policyData: this.order.policy.policyData, + isItac: isITAC, + insured: { + firstName: this.order.customer.firstName, + lastName: this.order.customer.lastName, + address: { + addressLine1: this.order.customer.address.streetAddress, + addressLine2: this.order.customer.address.streetAddress2, + city: this.order.customer.address.city, + state: this.order.customer.address.state, + zipCode: this.order.customer.address.zipCode, + country: 'US' // TODO set from store + }, + homePhone: { + number: this.contactInfo.homePhone?.replaceAll(nonNumberCharRegex, '') ?? '' + } }, - homePhone: { - number: this.contactInfo.homePhone?.replaceAll(nonNumberCharRegex, '') ?? '' + driver: { + firstName: this.order.customer.firstName, + lastName: this.order.customer.lastName + }, + caller: { + homePhone: {} + }, + policyInfo: { + policyNumber: this.order.policy.policyNumber, + safelitePolicy: { + policies: [] + }, + actualDeductible: this.currentDeductible.toString() ?? '' + }, + lossInfo: { + dateOfLoss: this.order.policy.dateOfLoss, + location: { + city: this.order.policy.damageCity, + state: this.order.policy.damageState, + country: 'US' // TODO set from store + }, + vehicle: { + id: this.order.vehicle.policyVehicleId?.toString() ?? '', + year: this.order.vehicle.year?.toString() ?? '', + make: this.order.vehicle.make, + model: this.order.vehicle.model, + vin: this.order.vehicle.vin + }, + cause: this.order.policy.damageCause, + damageDescription: this.order.policy.damageCause } }, - driver: { - firstName: this.order.customer.firstName, - lastName: this.order.customer.lastName - }, - caller: { - homePhone: {} - }, - policyInfo: { - policyNumber: this.order.policy.policyNumber, - safelitePolicy: { - policies: [] - }, - actualDeductible: this.currentDeductible.toString() ?? '' - }, - lossInfo: { - dateOfLoss: this.order.policy.dateOfLoss, - location: { - city: this.order.policy.damageCity, - state: this.order.policy.damageState, - country: 'US' // TODO set from store - }, - vehicle: { - id: this.order.vehicle.policyVehicleId?.toString() ?? '', - year: this.order.vehicle.year?.toString() ?? '', - make: this.order.vehicle.make, - model: this.order.vehicle.model, - vin: this.order.vehicle.vin - }, - cause: this.order.policy.damageCause, - damageDescription: this.order.policy.damageCause - } - } - }).then((response) => { - this.order.insuranceCoverage.claimNumber = response.data.claimNumber; - if (response.data.isSuccess) { - this.updateCoverageStatus(coverageStatuses.VERIFIED); - } else { - this.updateCoverageStatus(coverageStatuses.NO_COVERAGE); - } - return resolve(response); - }, (error) => { - this.updateCoverageStatus(coverageStatuses.NO_COVERAGE); - this.order.insuranceCoverage.claimNumber = null; - return reject(error); + bailoutOnError: false }); - }); + this.order.insuranceCoverage.claimNumber = response.data.claimNumber; + if (response.data.isSuccess) { + this.updateCoverageStatus(coverageStatuses.VERIFIED); + } else { + this.updateCoverageStatus(coverageStatuses.NO_COVERAGE); + } + } catch (e) { + this.updateCoverageStatus(coverageStatuses.NO_COVERAGE); + this.order.insuranceCoverage.claimNumber = null; + } }, - getFinalDeductible() { + async getFinalDeductible() { const endorsementAnswersForPayload = []; const endorsementAnswers = this.order.policy.endorsementQuestionAnswers; if (endorsementAnswers) { @@ -692,9 +701,9 @@ export const useMainStore = defineStore({ glassInformation?.forEach((glassPiece) => { manualGlassNamesArray.push(glassPiece?.glassLocation?.toUpperCase()); }); - - return new Promise((resolve, reject) => { - globalMethods.callHttpClient({ + + try { + const r = await globalMethods.callHttpClient({ method: endpoints.FinalDeductible.method, endpoint: endpoints.FinalDeductible.url, payload: { @@ -716,16 +725,18 @@ export const useMainStore = defineStore({ vehicleVin: this.order.vehicle.vin, policyData: this.order.policy.policyData, isItac: this.isITAC - } - }).then((r) => { - this.order.policy.policyData = r.data.policyData; - this.updateDeductible(r.data); - return resolve(r); - }).catch((error) => reject(error)); - }); + }, + bailoutOnError: false + }); + this.order.policy.policyData = r.data.policyData; + this.updateDeductible(r.data); + return r; + } catch (e) { + this.updateCoverageStatus(CoverageStatuses.PENDING); + } }, - getDuplicateReferrals() { + async getDuplicateReferrals() { const params = new URLSearchParams({ parentAccountNumber: this.order.parentAccountNumber, customerPhoneNumber: this.order.contactInfo.servicePhone, @@ -734,18 +745,16 @@ export const useMainStore = defineStore({ dateOfLoss: this.order.policy.dateOfLoss }); - return new Promise((resolve, reject) => { - globalMethods.callHttpClient({ + try { + const duplicates = await globalMethods.callHttpClient({ method: endpoints.DuplicateSearch.method, - endpoint: `${endpoints.DuplicateSearch.url}?${params.toString()}` - }).then((r) => { - this.applicationUser.duplicateOrders = r.data ?? []; - return resolve(r.data); - }).catch((error) => { - this.applicationUser.duplicateOrders = []; - return reject(error); + endpoint: `${endpoints.DuplicateSearch.url}?${params.toString()}`, + bailoutOnError: false }); - }); + this.applicationUser.duplicateOrders = duplicates.data ?? []; + } catch (e) { + this.applicationUser.duplicateOrders = []; + } }, async lookupVinByPlate(licensePlate, licenseState) { try { diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 24c6139f..0e0900d2 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -459,9 +459,9 @@ describe('Store', () => { expect(store.order.insuranceCoverage.claimNumber).not.toBeNull(); }); - it('Call to client returns exception, resulting in object with error property being returned', async () => { + it('Call to client returns exception, and no error is returned from registerClaim method', async () => { // Arrange - expect.assertions(4); + expect.assertions(3); const error = 'register claim error'; globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject(error)); store.order.insuranceCoverage.coverageStatus = coverageStatuses.PENDING; @@ -1494,8 +1494,8 @@ describe('Store', () => { // Assert expect(globalMethods.callHttpClient).toHaveBeenCalled(); }); - it('api call throws exception => insuranceCoverage.coverageType is NONE', async () => { - expect.assertions(3); + it('api call throws exception => no error is thrown from getCoveragePolicyInfo and insuranceCoverage.coverageType is NONE', async () => { + expect.assertions(2); const error = 'get coverage policy info error'; store.issConfig.isCoverageEnabled = true; store.applicationUser.coverageLookupAttempts = 0; @@ -1567,9 +1567,9 @@ describe('Store', () => { expect(globalMethods.callHttpClient).toHaveBeenCalled(); expect(store.applicationUser.duplicateOrders).toEqual(expected); }); - it('Call to client returns exception => object with error property returned and duplicateReferrals set to []', async () => { + it('Call to client returns exception => object with error property returned and duplicateReferrals set to [] and no error is returned from getDuplicateReferrals', async () => { // Arrange - expect.assertions(3); + expect.assertions(2); const error = 'get duplicate referrals error'; globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject(error)); @@ -1807,7 +1807,8 @@ describe('Store', () => { vehicleVin, policyData, isItac: store.isITAC - }) + }), + bailoutOnError: false })); }); it('only "Yes" endorsement answers are added to payload', () => { @@ -1912,14 +1913,15 @@ describe('Store', () => { vehicleVin, policyData, isItac: store.isITAC - }) + }), + bailoutOnError: false })); }); }); describe('unsuccessful api call', () => { - it('api call throws exception', async () => { + it('api call throws exception. no error from getFinalDeductible', async () => { // Arrange - expect.assertions(2); + expect.assertions(1); const error = 'final deductible error'; globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject(error)); @@ -2078,8 +2080,8 @@ describe('Store', () => { expect(result.data.shopProviders[1]).toBe(provider2); }); }); - it('api call throws exception => coverageType none', async () => { - expect.assertions(3); + it('api call throws exception => coverageType none and no error from getCoveragePolicyInfo', async () => { + expect.assertions(2); const error = 'get coverage policy info error'; store.issConfig.isCoverageEnabled = true;