From b7f0f0f74899bede0b9557261269b69f26f794b8 Mon Sep 17 00:00:00 2001 From: Johan Gunawan Date: Fri, 12 Apr 2024 14:30:04 -0400 Subject: [PATCH] SSR-659. Replace hard-coded BillToNumber. (#615) --- .eslintrc.js | 3 +- src/constants/application-config.js | 2 -- src/constants/endpoints.js | 18 ++++++---- src/layouts/entry-page/entry-page.vue | 40 ++++++++++++---------- src/layouts/welcome-page/welcome-page.vue | 41 +++++++++++++++++++++++ src/store/index.js | 39 ++++++++++++++------- src/store/store.spec.js | 38 ++++++++++++++++++++- 7 files changed, 141 insertions(+), 40 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 33b69824..7187e7e5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -45,7 +45,8 @@ module.exports = { }], 'import/extensions': ['error', 'always', { js: 'ignorePackages' }], 'no-param-reassign': ['error', { props: true, ignorePropertyModificationsFor: ['item'] }], - 'no-restricted-syntax': ['off', 'ForOfStatement'] + 'no-restricted-syntax': ['off', 'ForOfStatement'], + 'no-return-await': 'off' }, settings: { 'import/resolver': { diff --git a/src/constants/application-config.js b/src/constants/application-config.js index f6797d9d..c445bcf4 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -19,8 +19,6 @@ const applicationConfig = Object.freeze({ SAFELITE_HOP: process.env.VUE_APP_SAFELITE_HOP, ISS_DEV_CMS_DOMAIN: 'https://digitalisscms.dev.safelite.io', CASH_PARENT_ACCOUNT_NUMBER: 167132, - ITAC_FAIR_AND_REASONABLE_BILLTO: '214616', // Lib Mutal FnR BillTo - ITAC_CASH_BILLTO: '283393', // Lib Mutal ITAC Cash BillTo GOOGLE_CALENDAR: 'https://www.google.com/calendar/render?action=TEMPLATE', YAHOO_CALENDAR: 'https://calendar.yahoo.com/?v=60', OUTLOOK_CALENDAR: diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 770048e3..2466392d 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -1,15 +1,15 @@ -const CONTENT_BASE_URL = '/content/api/v1/content'; -const LOCATION_BASE_URL = '/location/api/v1/location'; -const SCHEDULE_BASE_URL = '/schedule/api/v1/schedule'; -const PARTS_BASE_URL = '/parts/api/v1/parts'; -const VEHICLE_BASE_URL = '/vehicle/api/v1/vehicle'; -const PRICE_BASE_URL = '/price/api/v1/price'; const ACCOUNT_BASE_URL = '/account/api/v1/account'; -const EXPERIMENTS_BASE_URL = '/experiments/api/v1/experiments'; const ANALYTICS_BASE_URL = '/analytics/api/v1/analytics'; const CLIENT_AUTH_BASE_URL = '/clientauth/api/v1/clientauth'; +const CONTENT_BASE_URL = '/content/api/v1/content'; const COVERAGE_BASE_URL = '/coverage/api/v1/coverage'; +const EXPERIMENTS_BASE_URL = '/experiments/api/v1/experiments'; +const LOCATION_BASE_URL = '/location/api/v1/location'; const ORDER_BASE_URL = '/order/api/v1/order'; +const PARTS_BASE_URL = '/parts/api/v1/parts'; +const PRICE_BASE_URL = '/price/api/v1/price'; +const SCHEDULE_BASE_URL = '/schedule/api/v1/schedule'; +const VEHICLE_BASE_URL = '/vehicle/api/v1/vehicle'; const endpoints = Object.freeze({ GetRouteInfo: { @@ -24,6 +24,10 @@ const endpoints = Object.freeze({ url: (applicationAbbreviation, pageName) => `${CONTENT_BASE_URL}/${applicationAbbreviation}/${pageName}`, method: 'GET' }, + GetBillToInfo: { + url: `${ACCOUNT_BASE_URL}/bill-to-info`, + method: 'POST' + }, GetAlertReasons: { url: `${LOCATION_BASE_URL}/alert-reasons`, method: 'GET' diff --git a/src/layouts/entry-page/entry-page.vue b/src/layouts/entry-page/entry-page.vue index a060ab39..76eaee1a 100644 --- a/src/layouts/entry-page/entry-page.vue +++ b/src/layouts/entry-page/entry-page.vue @@ -30,8 +30,25 @@ export default { }, computed: { }, - mounted() { - this.validateClientTagOnEntry(); + async mounted() { + const queryStringParams = this.parseQueryParms(); + + const { isAuthorized, clientData } = await this.validateClientTagOnEntry(queryStringParams); + + this.unauthorized = !isAuthorized; + + if (isAuthorized) { + await this.populateISSConfigValues(clientData); + + if (clientData.parameters?.length > 0) { + const finalParams = this.combineClientParameters(clientData.parameters, queryStringParams); + this.populateStoreItemsFromParams(finalParams); + } + + this.mainStore.applicationUser.coverageAttempts = 0; + // Forced full location redirect here. We do not want the entry page as part of the router/flow/path history. + window.location = `/?issPage=${issPageValues.WELCOME_PAGE}`; + } }, methods: { @@ -53,11 +70,11 @@ export default { return queryStringParams; }, - async validateClientTagOnEntry() { - const queryStringParams = this.parseQueryParms(); + async validateClientTagOnEntry(queryStringParams) { const clientTag = queryStringParams.clienttag; const clientTagPresent = !!clientTag; let authorized = false; + let clientData = null; if (clientTagPresent) { const resp = await validateISSClientTag(clientTag); @@ -76,23 +93,12 @@ export default { } if (authorized) { - await this.populateISSConfigValues(resp.data); - - if (resp.data.parameters?.length > 0) { - const finalParams = this.combineClientParameters(resp.data.parameters, queryStringParams); - this.populateStoreItemsFromParams(finalParams); - } + clientData = resp.data; } } } - this.unauthorized = !authorized; - - if (authorized) { - this.mainStore.applicationUser.coverageAttempts = 0; - // Forced full location redirect here. We do not want the entry page as part of the router/flow/path history. - window.location = `/?issPage=${issPageValues.WELCOME_PAGE}`; - } + return { isAuthorized: authorized, clientData }; }, async populateISSConfigValues(data) { this.mainStore.issConfig.clientName = data.accountName; diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index e8a6bddb..d2b1cd0b 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -197,6 +197,8 @@ import states from '@/constants/states'; import globalRules from '@/constants/global-rules'; import routerParams from '@/router/router-constants/router-params'; import MaskaFormattedMasks from '@/constants/maska-masks'; +import globalMethods from '@/global-methods'; +import { endpoints } from '@/constants/endpoints'; // define validation rules defineRule('damage-option-required', required(errorMessages.DAMAGE_OPTION_REQUIRED)); @@ -323,6 +325,20 @@ export default { .then(async (zipInfo) => { if (zipInfo?.data?.isValid === true) { this.mainStore.updatePolicyData(this.welcomePageModel); + + this.mainStore.order.serviceLocation.zipCodeCtu = zipInfo.data.zipCodeCtu?.toString(); + + const billToInfo = await this.getBillToInfo( + this.mainStore.issConfig.parentAccountNumber, + this.mainStore.order.serviceLocation.zipCodeCtu + ); + + if (billToInfo !== null) { + this.mainStore.issConfig.billToAccountNumber = billToInfo.billToAccountNumber; + this.mainStore.issConfig.itacCashBillToNumber = billToInfo.itacCashBillToNumber; + this.mainStore.issConfig.itacFnrBillToNumber = billToInfo.itacFnrBillToNumber; + } + await this.mainStore.getDuplicateReferrals() .then(() => {}, () => {}) .finally(async () => { @@ -339,6 +355,31 @@ export default { } }); }, + + async getBillToInfo(parentAccountNumber, providerNumber) { + try { + const payload = { + parentAccountNumber: parentAccountNumber.toString(), + providerNumber: providerNumber.toString(), + billToSelectionCriteria: { + typeOfClaim: 'GLASS ONLY', + lineOfBusiness: 'PERSONAL' + } + }; + + const response = await globalMethods.callHttpClient({ + method: endpoints.GetBillToInfo.method, + endpoint: endpoints.GetBillToInfo.url, + payload + }); + + return response.data; + } catch (err) { + console.error(`Error Status Code: ${err.data?.status}: ${err.data?.title}`); + return null; + } + }, + navigateForward() { if (this.mainStore.applicationUser.duplicateOrders?.length > 0 ?? false) { this.$router.navigate( diff --git a/src/store/index.js b/src/store/index.js index c3728ae3..c6a8f713 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -228,6 +228,9 @@ export const getDefaultState = () => ({ clientHeader: {}, styleSheet: '', // Stylesheet used by the client. parentAccountNumber: 0, // Parent account number used by the client. + billToAccountNumber: null, + itacCashBillToNumber: null, + itacFnrBillToNumber: null, isCoverageEnabled: false, // Indicates if we should be calling coverage on this flow. isClaimRegistrationRequired: false, // Indicates if the claim registration call needs to be made for a client to complete coverage verification. isAuthenticated: false, // Indicates if user is authenticated or not. @@ -249,9 +252,20 @@ export const useMainStore = defineStore({ id: storeId, state: () => state, getters: { - hasRecalibrationPart: (state) => getHasRecalibrationPart(state), - vehicle: (state) => state.order.vehicle, - damage: (state) => state.order.damage, + billToNumberToUse(storeState) { + if (this.isITAC) { + return storeState.issConfig.itacCashBillToNumber; + } + + if (this.isNoComp) { + return storeState.issConfig.itacFnrBillToNumber; + } + + return storeState.issConfig.billToAccountNumber; + }, + hasRecalibrationPart: (storeState) => getHasRecalibrationPart(storeState), + vehicle: (storeState) => storeState.order.vehicle, + damage: (storeState) => storeState.order.damage, lineItems: (state) => state.order.lineItems, payment: (state) => state.order.payment, policy: (state) => state.order.policy, @@ -817,7 +831,7 @@ export const useMainStore = defineStore({ startDate, endDate, applicationName: applicationConfig.APPLICATION_NAME, - billToAccountNumber: this.issConfig.parentAccountNumber.toString(), // TODO: MAKE THIS REAL + billToAccountNumber: this.billToNumberToUse, parentAccountNumber: this.issConfig.parentAccountNumber, // this.payment.parentAccountNumber, carId: vehicle.carId, lineItems, @@ -880,7 +894,7 @@ export const useMainStore = defineStore({ endDate, shopAppointmentType, applicationName: applicationConfig.APPLICATION_NAME, - billToAccountNumber: order.policy.isITAC ? applicationConfig.ITAC_CASH_BILLTO : applicationConfig.ITAC_FAIR_AND_REASONABLE_BILLTO, // TODO: MAKE THIS REAL + billToAccountNumber: this.billToNumberToUse, parentAccountNumber: this.issConfig.parentAccountNumber, // this.payment.parentAccountNumber, carId: vehicle.carId, lineItems, @@ -1005,6 +1019,7 @@ export const useMainStore = defineStore({ let queryString = `ParentAccountNumber=${this.order.accountNumber}` + + `&BillToAccountNumber=${this.billToNumberToUse}` + `&CTU=${ctuToUse}` + `&Deductible=${deductibleToUse}` + `&ZipCode=${zipCodeToUse}` @@ -1033,12 +1048,10 @@ export const useMainStore = defineStore({ getMobileFeePart() { const damageType = this.damage.isRepair ? 'Repair' : 'Replace'; - const parentAccountNumber = 167132; // TODO: MAKE THIS REAL - const billToAccountNumber = 87291; // TODO: MAKE THIS REAL return globalMethods.callHttpClient({ method: endpoints.GetMobileFeePart.method, - endpoint: `${endpoints.GetMobileFeePart.url}/${damageType}/${parentAccountNumber}/${billToAccountNumber}` + endpoint: `${endpoints.GetMobileFeePart.url}/${damageType}/${this.order.accountNumber}/${this.billToNumberToUse}` }); }, @@ -1678,6 +1691,9 @@ export const useMainStore = defineStore({ this.issConfig.disabledFields.policyZipCode = false; this.issConfig.disabledFields.dateOfLoss = false; this.issConfig.siteType = null; + this.issConfig.billToAccountNumber = null; + this.issConfig.itacCashBillToNumber = null; + this.issConfig.itacFnrBillToNumber = null; }, disableKeyFields() { @@ -1881,7 +1897,7 @@ export const useMainStore = defineStore({ const { vehicle } = this.order; let queryString = - `ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` + `ParentAccountNumber=${this.order.accountNumber}` + `&CTU=${ctuToUse}` + `&CarId=${vehicle.carId}` + `&Make=${vehicle.make}` @@ -1908,7 +1924,6 @@ export const useMainStore = defineStore({ async taxOrderItemsAndSaveServerData(pricedLineItems) { const { order } = this; const { serviceLocation } = order; - const billToAccountNumber = this.issConfig.parentAccountNumber.toString(); // payment const { providerNumber } = serviceLocation.provider; const { appointmentType } = serviceLocation; const serviceLocationCity = serviceLocation.city; @@ -1934,7 +1949,7 @@ export const useMainStore = defineStore({ || appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) { queryString = `ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` - + `&BillToAccountNumber=${billToAccountNumber}` + + `&BillToAccountNumber=${this.billToNumberToUse}` + `&ProviderNumber=${providerNumber}` + `&AppointmentType=${appointmentType}` + `&ServiceLocation.City=${serviceLocationCity}` @@ -1944,7 +1959,7 @@ export const useMainStore = defineStore({ } else { queryString = `ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` - + `&BillToAccountNumber=${billToAccountNumber}` + + `&BillToAccountNumber=${this.billToNumberToUse}` + `&ProviderNumber=${providerNumber}` + `&AppointmentType=${appointmentType}` + `&${pricedLineItemsFormattedForRequest}`; diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 8c7382ff..6499d98a 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -1,5 +1,5 @@ import { setActivePinia, createPinia } from 'pinia'; -import { useMainStore } from '@/store/index.js'; +import { useMainStore, getDefaultState } from '@/store/index.js'; import globalMethods from '@/global-methods.js'; import { getRandomString, getRandomGuid, getRandomInt, getRandomBoolean } from '@/helpers/data-generation.js'; import coverageStatuses from '@/constants/coverage-statuses.js'; @@ -14,7 +14,13 @@ describe('Store', () => { beforeEach(() => { const pinia = createPinia(); setActivePinia(pinia); + store = useMainStore(); + const defaultState = getDefaultState(); + Object.keys(defaultState).forEach((key) => { + store[key] = defaultState[key]; + }); + store.applicationUser.eventBus = []; jest.resetAllMocks(); }); @@ -1969,4 +1975,34 @@ describe('Store', () => { expect(store.order.payment.paypalToken).toEqual(paypalToken); }); }); + + describe('billToNumberToUse getter', () => { + it('returns itacCashBillToNumber when in ITAC flow', () => { + // Arrange + store.order.policy.isITAC = true; + store.issConfig.itacCashBillToNumber = '12345'; + + // Assert + expect(store.billToNumberToUse).toEqual(store.issConfig.itacCashBillToNumber); + }); + + it('returns itacFnrBillToNumber when in NoComp flow', () => { + // Arrange + store.order.policy.noCoverage = true; + store.issConfig.itacFnrBillToNumber = '12345'; + + // Assert + expect(store.billToNumberToUse).toEqual(store.issConfig.itacFnrBillToNumber); + }); + + it('returns billToAccountNumber when not ITAC and not NoComp', () => { + // Arrange + store.order.policy.isITAC = null; + store.order.policy.noCoverage = null; + store.issConfig.billToAccountNumber = '12345'; + + // Assert + expect(store.billToNumberToUse).toEqual(store.issConfig.billToAccountNumber); + }); + }); });