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/contact-details/contact-details.spec.js b/src/layouts/contact-details/contact-details.spec.js index 7930b319..58d16b8e 100644 --- a/src/layouts/contact-details/contact-details.spec.js +++ b/src/layouts/contact-details/contact-details.spec.js @@ -160,14 +160,16 @@ describe('contactDetails.vue', () => { const firstName = getRandomString(4, 15); const lastName = getRandomString(4, 15); const emailAddress = getRandomString(10, 20); - const phoneNumber = getRandomInt(1000000000, 9999999999); + const servicePhone = getRandomInt(1000000000, 9999999999).toString(); const mainInitialState = { order: { customer: { firstName, lastName, - emailAddress, - phoneNumber + emailAddress + }, + contactInfo: { + servicePhone } } }; @@ -185,7 +187,7 @@ describe('contactDetails.vue', () => { expect(wrapper.vm.firstName).toBe(firstName); expect(wrapper.vm.lastName).toBe(lastName); expect(wrapper.vm.emailAddress).toBe(emailAddress); - expect(wrapper.vm.phoneNumber).toBe(phoneNumber); + expect(wrapper.vm.phoneNumber).toBe(servicePhone); }); test('Mock store with contact info yields expected data', () => { // Arrange @@ -199,7 +201,7 @@ describe('contactDetails.vue', () => { firstName: getRandomString(4, 15), lastName: getRandomString(4, 15), emailAddress: getRandomString(10, 20), - phoneNumber: getRandomInt(1000000000, 9999999999), + servicePhone: getRandomInt(1000000000, 9999999999), requestTextUpdates: getRandomBoolean(), notesForTechnician: getRandomString(50, 100) }; @@ -224,7 +226,7 @@ describe('contactDetails.vue', () => { expect(wrapper.vm.firstName).toBe(contactInfo.firstName); expect(wrapper.vm.lastName).toBe(contactInfo.lastName); expect(wrapper.vm.emailAddress).toBe(contactInfo.emailAddress); - expect(wrapper.vm.phoneNumber).toBe(contactInfo.phoneNumber); + expect(wrapper.vm.phoneNumber).toBe(contactInfo.servicePhone); expect(wrapper.vm.requestTextUpdates).toBe(contactInfo.requestTextUpdates); expect(wrapper.vm.notesForTechnician).toBe(contactInfo.notesForTechnician); }); @@ -315,7 +317,7 @@ describe('contactDetails.vue', () => { const firstName = getRandomString(4, 15); const lastName = getRandomString(4, 15); const emailAddress = getRandomString(10, 20); - const phoneNumber = getRandomInt(1000000000, 9999999999); + const phoneNumber = getRandomInt(1000000000, 9999999999).toString(); const requestTextUpdates = getRandomBoolean(); const notesForTechnician = getRandomString(1, 100); wrapper.setData({ @@ -335,11 +337,60 @@ describe('contactDetails.vue', () => { firstName, lastName, emailAddress, - phoneNumber, requestTextUpdates, notesForTechnician }); }); + + test('Forward button click updates phone numbers request text updates', () => { + // Arrange + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + const wrapper = shallowMount(contactDetails, mountOptions); + const phoneNumber = getRandomInt(1000000000, 9999999999).toString(); + const requestTextUpdates = true; + wrapper.setData({ + phoneNumber, + requestTextUpdates + }); + + // Act + wrapper.vm.forwardButtonAction(); + + // Assert + expect(useMainStore().updatePhoneNumbers).toHaveBeenCalledWith({ + service: phoneNumber, + alternative: phoneNumber + }); + }); + + test('Forward button click updates phone numbers dot not request text updates', () => { + // Arrange + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + const wrapper = shallowMount(contactDetails, mountOptions); + const phoneNumber = getRandomInt(1000000000, 9999999999).toString(); + const requestTextUpdates = false; + wrapper.setData({ + phoneNumber, + requestTextUpdates + }); + + // Act + wrapper.vm.forwardButtonAction(); + + // Assert + expect(useMainStore().updatePhoneNumbers).toHaveBeenCalledWith({ + home: phoneNumber, + service: phoneNumber + }); + }); }); test('Mocked store with no contact info yields expected data', () => { @@ -349,20 +400,19 @@ describe('contactDetails.vue', () => { const firstName = getRandomString(4, 15); const lastName = getRandomString(4, 15); const emailAddress = getRandomString(10, 20); - const phoneNumber = getRandomInt(1000000000, 9999999999); + const servicePhone = getRandomInt(1000000000, 9999999999); const mainInitialState = { order: { customer: { firstName, lastName, - emailAddress, - phoneNumber + emailAddress }, contactInfo: { firstName: null, lastName: null, emailAddress: null, - phoneNumber: null, + servicePhone, requestTextUpdates: null, notesForTechnician: null } @@ -382,7 +432,7 @@ describe('contactDetails.vue', () => { expect(wrapper.vm.firstName).toBe(firstName); expect(wrapper.vm.lastName).toBe(lastName); expect(wrapper.vm.emailAddress).toBe(emailAddress); - expect(wrapper.vm.phoneNumber).toBe(phoneNumber); + expect(wrapper.vm.phoneNumber).toBe(servicePhone); }); test('Mock store with contact info yields expected data', () => { @@ -397,7 +447,7 @@ describe('contactDetails.vue', () => { firstName: getRandomString(4, 15), lastName: getRandomString(4, 15), emailAddress: getRandomString(10, 20), - phoneNumber: getRandomInt(1000000000, 9999999999), + servicePhone: getRandomInt(1000000000, 9999999999), requestTextUpdates: getRandomBoolean(), notesForTechnician: getRandomString(50, 100) }; @@ -422,7 +472,7 @@ describe('contactDetails.vue', () => { expect(wrapper.vm.firstName).toBe(contactInfo.firstName); expect(wrapper.vm.lastName).toBe(contactInfo.lastName); expect(wrapper.vm.emailAddress).toBe(contactInfo.emailAddress); - expect(wrapper.vm.phoneNumber).toBe(contactInfo.phoneNumber); + expect(wrapper.vm.phoneNumber).toBe(contactInfo.servicePhone); expect(wrapper.vm.requestTextUpdates).toBe(contactInfo.requestTextUpdates); expect(wrapper.vm.notesForTechnician).toBe(contactInfo.notesForTechnician); }); diff --git a/src/layouts/contact-details/contact-details.vue b/src/layouts/contact-details/contact-details.vue index dcca28ee..ceec1259 100644 --- a/src/layouts/contact-details/contact-details.vue +++ b/src/layouts/contact-details/contact-details.vue @@ -139,14 +139,14 @@ export default { const { firstName, lastName, emailAddress, - phoneNumber, + servicePhone, requestTextUpdates, notesForTechnician } = useMainStore().contactInfo; return { firstName, lastName, emailAddress, - phoneNumber, + phoneNumber: servicePhone, requestTextUpdates, notesForTechnician, widget: { @@ -196,11 +196,23 @@ export default { firstName: this.firstName, lastName: this.lastName, emailAddress: this.emailAddress, - phoneNumber: this.phoneNumber, requestTextUpdates: this.requestTextUpdates, notesForTechnician: this.notesForTechnician }; useMainStore().updateContactInfo(contactInfo); + + if (this.requestTextUpdates) { + useMainStore().updatePhoneNumbers({ + service: this.phoneNumber, + alternative: this.phoneNumber + }); + } else { + useMainStore().updatePhoneNumbers({ + home: this.phoneNumber, + service: this.phoneNumber + }); + } + const scenario = useMainStore().order.serviceLocation.IsSafeliteProvider === false ? this.navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP : this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP; diff --git a/src/layouts/entry-page/entry-page.vue b/src/layouts/entry-page/entry-page.vue index b2da8ab2..29475742 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/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index c38a062e..2eb8208e 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -76,7 +76,7 @@ const initialStore = { contactInfo: { firstName: 'Test', lastName: 'Test', - phoneNumber: '111-111-1111', + servicePhone: '111-111-1111', emailAddress: 'test@email.com' } } diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index c045f651..b7e1af75 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -318,7 +318,7 @@ export default { const contactInfoReqs = !!( contactInfo.firstName && contactInfo.lastName - && contactInfo.phoneNumber + && contactInfo.servicePhone && contactInfo.emailAddress ); diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index a743b180..cb5605a5 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -241,14 +241,22 @@ export default { ); // Customer - const { firstName, lastName, phoneNumber, emailAddress } = useMainStore().order.customer; + const { firstName, lastName, emailAddress } = useMainStore().order.customer; const customerReqs = !!( firstName && lastName - && phoneNumber && emailAddress ); + // Contact Info + const { contactInfo } = useMainStore().order; + const contactInfoReqs = !!( + contactInfo.firstName + && contactInfo.lastName + && contactInfo.servicePhone + && contactInfo.emailAddress + ); + return ( vehicleReqs && damageReqs @@ -256,6 +264,7 @@ export default { && serviceLocationReqs && scheduleReqs && customerReqs + && contactInfoReqs ); }, getPaymentMethodFromStore() { diff --git a/src/layouts/payment-page/payment-page.spec.js b/src/layouts/payment-page/payment-page.spec.js index 2e2f62ef..661d656c 100644 --- a/src/layouts/payment-page/payment-page.spec.js +++ b/src/layouts/payment-page/payment-page.spec.js @@ -183,7 +183,7 @@ describe('payment-page.vue', () => { firstName: 'first', lastName: 'last', emailAddress: 'builddigitaltest@safelite.com', - phoneNumber: '555-555-5555' + servicePhone: '555-555-5555' }, damage: { isRepair: false, diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index d8b6d3b5..2642ccca 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -500,7 +500,7 @@ export default { zipCode: this.getZipCode(), firstName: useMainStore().order.contactInfo.firstName, lastName: useMainStore().order.contactInfo.lastName, - phoneNumber: useMainStore().order.contactInfo.phoneNumber, + phoneNumber: useMainStore().order.contactInfo.servicePhone, ctu: useMainStore().order.serviceLocation.zipCodeCtu, referralCorrelationId: useMainStore().order.referralCorrelationId, workOrderNumber: this.getWorkOrderNumber(), @@ -597,7 +597,7 @@ export default { const contactInfoReqs = !!( contactInfo.firstName && contactInfo.lastName - && contactInfo.phoneNumber + && contactInfo.servicePhone && contactInfo.emailAddress ); diff --git a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js index e814af3d..9c579dbc 100644 --- a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js +++ b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js @@ -35,14 +35,14 @@ describe('contact-details-drawer', () => { const firstName = 'Frederick'; const lastName = 'Taylor'; const emailAddress = 'fred.tay@gmail.com'; - const phoneNumber = '606-009-2943'; + const servicePhone = '606-009-2943'; const mainInitialState = { order: { contactInfo: { firstName, lastName, emailAddress, - phoneNumber + servicePhone } } }; @@ -81,7 +81,7 @@ describe('contact-details-drawer', () => { firstName: 'Frederick', lastName: 'Taylor', emailAddress: 'fred.tay@gmail.com', - phoneNumber: '606-009-2943' + servicePhone: '606-009-2943' } } }; @@ -96,7 +96,9 @@ describe('contact-details-drawer', () => { // Assert expect(wrapper.emitted()['update-contact-details']).toBeTruthy(); expect(useMainStore().updateContactInfo).toBeCalledTimes(1); - expect(useMainStore().updateContactInfo).toBeCalledWith({ firstName, lastName, emailAddress, phoneNumber }); + expect(useMainStore().updateContactInfo).toBeCalledWith({ firstName, lastName, emailAddress }); + expect(useMainStore().updatePhoneNumbers).toBeCalledTimes(1); + expect(useMainStore().updatePhoneNumbers).toBeCalledWith({ home: phoneNumber, service: phoneNumber }); } ); }); diff --git a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue index 5f1b0b6f..334ba86a 100644 --- a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue +++ b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue @@ -67,13 +67,13 @@ export default { const { firstName, lastName, emailAddress, - phoneNumber } = useMainStore().contactInfo; + servicePhone } = useMainStore().contactInfo; return { isModalOpened: false, firstName, lastName, emailAddress, - phoneNumber, + phoneNumber: servicePhone, widget: { title: 'ContactDetailsDrawerHeaderWidget', firstNameQuestion: 'FirstNameQuestionWidget', @@ -119,21 +119,24 @@ export default { const contactInfo = { firstName: this.firstName, lastName: this.lastName, - emailAddress: this.emailAddress, - phoneNumber: this.phoneNumber + emailAddress: this.emailAddress }; useMainStore().updateContactInfo(contactInfo); + useMainStore().updatePhoneNumbers({ + home: this.phoneNumber, + service: this.phoneNumber + }); this.$emit('update-contact-details'); }, resetFormValues() { const { firstName, lastName, emailAddress, - phoneNumber } = useMainStore().contactInfo; + servicePhone } = useMainStore().contactInfo; this.firstName = firstName; this.lastName = lastName; this.emailAddress = emailAddress; - this.phoneNumber = phoneNumber; + this.phoneNumber = servicePhone; }, openModal() { this.modal.openModal(); diff --git a/src/layouts/tpa-submit/tpa-submit.spec.js b/src/layouts/tpa-submit/tpa-submit.spec.js index aaadc048..d3bece6b 100644 --- a/src/layouts/tpa-submit/tpa-submit.spec.js +++ b/src/layouts/tpa-submit/tpa-submit.spec.js @@ -499,14 +499,14 @@ describe('tpa-submit', () => { const firstName = 'Jones'; const lastName = 'Eddison'; const emailAddress = 'myname@gmail.com'; - const phoneNumber = '0001112222'; + const servicePhone = '0001112222'; const initialStore = { order: { contactInfo: { firstName, lastName, emailAddress, - phoneNumber + servicePhone } } }; @@ -514,7 +514,7 @@ describe('tpa-submit', () => { const expectedLine1 = 'Jones Eddison'; const expectedLine2 = emailAddress; const expectedLine3 = 'some value returned'; - toDisplayPhoneNumber.mockImplementation((number) => (number === phoneNumber ? expectedLine3 : '')); + toDisplayPhoneNumber.mockImplementation((number) => (number === servicePhone ? expectedLine3 : '')); const contactInfoSectionIndex = 3; // Act @@ -530,7 +530,7 @@ describe('tpa-submit', () => { expect(contactInfoSection.lines[0]).toBe(expectedLine1); expect(contactInfoSection.lines[1]).toBe(expectedLine2); expect(contactInfoSection.lines[2]).toBe(expectedLine3); - expect(toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber); + expect(toDisplayPhoneNumber).toHaveBeenCalledWith(servicePhone); }); }); describe('computed', () => { diff --git a/src/layouts/tpa-submit/tpa-submit.vue b/src/layouts/tpa-submit/tpa-submit.vue index 590a4645..fda79826 100644 --- a/src/layouts/tpa-submit/tpa-submit.vue +++ b/src/layouts/tpa-submit/tpa-submit.vue @@ -236,11 +236,11 @@ export default { return [toTitleCase(this.companyName ?? ''), displayAddress, displayPhoneNumber]; }, getContactInfoLines() { - const { firstName, lastName, emailAddress, phoneNumber } = useMainStore().contactInfo; + const { firstName, lastName, emailAddress, servicePhone } = useMainStore().contactInfo; return [ `${firstName} ${lastName}`, emailAddress ?? '', - toDisplayPhoneNumber(phoneNumber) + toDisplayPhoneNumber(servicePhone) ]; } }, 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 7bf09725..396e38cf 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -119,8 +119,7 @@ export const getDefaultState = () => ({ }, firstName: null, lastName: null, - emailAddress: null, - phoneNumber: null + emailAddress: null }, serviceLocation: { address: null, @@ -182,7 +181,9 @@ export const getDefaultState = () => ({ firstName: null, lastName: null, emailAddress: null, - phoneNumber: null, + homePhone: null, + alternativePhone: null, + servicePhone: null, requestTextUpdates: false, notesForTechnician: '' }, @@ -227,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 +253,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, @@ -327,7 +342,9 @@ export const useMainStore = defineStore({ firstName: s.order.contactInfo.firstName ?? s.order.customer.firstName, lastName: s.order.contactInfo.lastName ?? s.order.customer.lastName, emailAddress: s.order.contactInfo.emailAddress ?? s.order.customer.emailAddress, - phoneNumber: s.order.contactInfo.phoneNumber ?? s.order.customer.phoneNumber, + homePhone: s.order.contactInfo.homePhone, + alternativePhone: s.order.contactInfo.alternativePhone, + servicePhone: s.order.contactInfo.servicePhone, requestTextUpdates: s.order.contactInfo.requestTextUpdates ?? false, notesForTechnician: s.order.contactInfo.notesForTechnician }), @@ -573,7 +590,7 @@ export const useMainStore = defineStore({ country: 'US' // TODO set from store }, homePhone: { - number: this.order.customer.phoneNumber?.replaceAll(nonNumberCharRegex, '') ?? '' + number: this.contactInfo.homePhone?.replaceAll(nonNumberCharRegex, '') ?? '' } }, driver: { @@ -833,7 +850,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, @@ -896,7 +913,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, @@ -1021,6 +1038,7 @@ export const useMainStore = defineStore({ let queryString = `ParentAccountNumber=${this.order.accountNumber}` + + `&BillToAccountNumber=${this.billToNumberToUse}` + `&CTU=${ctuToUse}` + `&Deductible=${deductibleToUse}` + `&ZipCode=${zipCodeToUse}` @@ -1049,12 +1067,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}` }); }, @@ -1223,7 +1239,7 @@ export const useMainStore = defineStore({ policyHolder: { policyFirstName: customer.firstName, policyLastName: customer.lastName, - policyPhoneNumber: customer.phoneNumber, + policyPhoneNumber: contactInfo.servicePhone, policyEmail: customer.emailAddress, policyState: customer.address.state }, @@ -1247,8 +1263,10 @@ export const useMainStore = defineStore({ emailAddress: contactInfo.emailAddress || customer.emailAddress, firstName: contactInfo.firstName || customer.firstName, lastName: contactInfo.lastName || customer.lastName, - phoneNumber: contactInfo.phoneNumber, - optInSms: contactInfo.requestTextUpdates ?? false + homePhone: contactInfo.homePhone, + servicePhone: contactInfo.servicePhone, + alternativePhone: contactInfo.alternativePhone, + isSmsOptIn: contactInfo.requestTextUpdates ?? false }, lineItems: { glassParts: lineItems.glassParts, @@ -1344,7 +1362,6 @@ export const useMainStore = defineStore({ order.customer.emailAddress = data.customer?.emailAddress; order.customer.firstName = data.customer?.firstName; order.customer.lastName = data.customer?.lastName; - order.customer.phoneNumber = data?.customer?.phoneNumber; order.customer.address.streetAddress = data.customer?.address?.streetAddress; order.customer.address.streetAddress2 = data.customer?.address?.streetAddress2; @@ -1355,7 +1372,8 @@ export const useMainStore = defineStore({ order.contactInfo.firstName = data?.customer?.firstName; order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; - order.contactInfo.phoneNumber = data?.customer?.phoneNumber; + order.contactInfo.homePhone = data?.customer?.phoneNumber; + order.contactInfo.servicephone = data?.customer?.phoneNumber; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; order.payment.insuranceCoverage.isVerified = data?.payment?.insuranceCoverage?.isVerified; @@ -1693,6 +1711,9 @@ export const useMainStore = defineStore({ this.issConfig.disabledFields.dateOfLoss = false; this.issConfig.siteType = null; this.issConfig.enableNoCompQuote = false; + this.issConfig.billToAccountNumber = null; + this.issConfig.itacCashBillToNumber = null; + this.issConfig.itacFnrBillToNumber = null; }, disableKeyFields() { @@ -1795,8 +1816,11 @@ export const useMainStore = defineStore({ this.order.policy.damageState = welcomePageModel?.damageState; this.order.policy.damageCity = welcomePageModel?.damageCity; this.order.policy.isDamageGlassOnly = welcomePageModel?.isDamageGlassOnly; - this.order.customer.phoneNumber = welcomePageModel?.phoneNumber; this.order.customer.emailAddress = welcomePageModel?.email; + this.updatePhoneNumbers({ + home: welcomePageModel?.phoneNumber, + service: welcomePageModel?.phoneNumber + }); }, updatePolicyHolderDetails(customerQuestions) { this.order.customer.address.streetAddress = customerQuestions.addressQuestions.streetAddress; @@ -1893,7 +1917,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}` @@ -1920,7 +1944,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; @@ -1946,7 +1969,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}` @@ -1956,7 +1979,7 @@ export const useMainStore = defineStore({ } else { queryString = `ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` - + `&BillToAccountNumber=${billToAccountNumber}` + + `&BillToAccountNumber=${this.billToNumberToUse}` + `&ProviderNumber=${providerNumber}` + `&AppointmentType=${appointmentType}` + `&${pricedLineItemsFormattedForRequest}`; @@ -2143,11 +2166,17 @@ export const useMainStore = defineStore({ this.order.contactInfo.firstName = contactInfo?.firstName ?? ''; this.order.contactInfo.lastName = contactInfo?.lastName ?? ''; this.order.contactInfo.emailAddress = contactInfo?.emailAddress ?? ''; - this.order.contactInfo.phoneNumber = contactInfo?.phoneNumber ?? ''; this.order.contactInfo.requestTextUpdates = contactInfo?.requestTextUpdates ?? false; this.order.contactInfo.notesForTechnician = contactInfo?.notesForTechnician ?? ''; }, + updatePhoneNumbers(phoneNumbers) { + const contact = this.order.contactInfo; + contact.homePhone = phoneNumbers.home !== undefined ? phoneNumbers.home : contact.homePhone; + contact.alternativePhone = phoneNumbers.alternative !== undefined ? phoneNumbers.alternative : contact.alternativePhone; + contact.servicePhone = phoneNumbers.service !== undefined ? phoneNumbers.service : contact.servicePhone; + }, + GetExperimentsByUser(userId) { return globalMethods.callHttpClient({ method: endpoints.GetExperimentsByUser.method, @@ -2299,8 +2328,11 @@ export const useMainStore = defineStore({ setBailoutContactInfo(contact) { this.order.customer.firstName = contact.firstName; this.order.customer.lastName = contact.lastName; - this.order.customer.phoneNumber = contact.phoneNumber; this.order.customer.emailAddress = contact.email; + this.updatePhoneNumbers({ + home: contact.phoneNumber, + service: contact.phoneNumber + }); this.pageData(issPageValues.BAILOUT_PAGE).submit = true; }, @@ -2331,7 +2363,6 @@ export const useMainStore = defineStore({ this.order.policy.damageCity = null; this.order.policy.damageState = null; this.order.policy.isITAC = false; - this.order.customer.phoneNumber = null; this.order.customer.emailAddress = null; this.order.customer.firstName = null; this.order.customer.lastName = null; diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 300ea4ea..c08b9dcf 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(); }); @@ -478,7 +484,6 @@ describe('Store', () => { const firstName = getRandomString(4, 10); const lastName = getRandomString(5, 15); const emailAddress = false; - const phoneNumber = getRandomInt(1000000000, 9999999999); const requestTextUpdates = getRandomBoolean(); const notesForTechnician = getRandomString(50, 150); @@ -486,7 +491,6 @@ describe('Store', () => { store.updateContactInfo({ firstName, lastName, emailAddress, - phoneNumber, requestTextUpdates, notesForTechnician }); @@ -494,10 +498,27 @@ describe('Store', () => { expect(store.contactInfo.firstName).toEqual(firstName); expect(store.contactInfo.lastName).toEqual(lastName); expect(store.contactInfo.emailAddress).toEqual(emailAddress); - expect(store.contactInfo.phoneNumber).toEqual(phoneNumber); expect(store.contactInfo.requestTextUpdates).toEqual(requestTextUpdates); expect(store.contactInfo.notesForTechnician).toEqual(notesForTechnician); }); + it('updatePhoneNumbers updates phone info in store', () => { + // Arrange + const homePhone = getRandomInt(1000000000, 9999999999); + const servicePhone = getRandomInt(1000000000, 9999999999); + const altPhone = getRandomInt(1000000000, 9999999999); + + // Act + store.updatePhoneNumbers({ + home: homePhone, + service: servicePhone, + alternative: altPhone + }); + + // Assert + expect(store.contactInfo.homePhone).toEqual(homePhone); + expect(store.contactInfo.servicePhone).toEqual(servicePhone); + expect(store.contactInfo.alternativePhone).toEqual(altPhone); + }); it('All null values => contact info set in store to all nulls', () => { // Act store.updateContactInfo({}); @@ -506,7 +527,6 @@ describe('Store', () => { expect(store.contactInfo.firstName).toEqual(''); expect(store.contactInfo.lastName).toEqual(''); expect(store.contactInfo.emailAddress).toEqual(''); - expect(store.contactInfo.phoneNumber).toEqual(''); expect(store.contactInfo.requestTextUpdates).toEqual(false); expect(store.contactInfo.notesForTechnician).toEqual(''); }); @@ -666,8 +686,9 @@ describe('Store', () => { store.order.customer.firstName = customerFirstName; store.order.customer.lastName = customerLastName; store.order.customer.emailAddress = customerEmail; - store.order.customer.phoneNumber = customerPhoneNumber; store.order.customer.address.state = customerState; + store.order.contactInfo.homePhone = customerPhoneNumber; + store.order.contactInfo.servicePhone = customerPhoneNumber; store.order.policy.policyNumber = policyNumber; store.order.policy.policyZipCode = policyZipCode; store.order.policy.policyLookupSuccessful = policyLookupSuccessful; @@ -708,12 +729,16 @@ describe('Store', () => { const contactFirstName = getRandomString(6, 6); const contactLastName = getRandomString(6, 6); const contactEmail = getRandomString(6, 6); - const contactPhoneNumber = getRandomString(6, 6); + const contactHomePhone = getRandomString(6, 6); + const contactServicePhone = getRandomString(6, 6); + const contactAlternativePhone = getRandomString(6, 6); const requestTextUpdates = getRandomBoolean(); store.order.contactInfo.firstName = contactFirstName; store.order.contactInfo.lastName = contactLastName; store.order.contactInfo.emailAddress = contactEmail; - store.order.contactInfo.phoneNumber = contactPhoneNumber; + store.order.contactInfo.homePhone = contactHomePhone; + store.order.contactInfo.servicePhone = contactServicePhone; + store.order.contactInfo.alternativePhone = contactAlternativePhone; store.order.contactInfo.requestTextUpdates = requestTextUpdates; store.order.customer.address.streetAddress = streetAddress; store.order.customer.address.streetAddress2 = streetAddress2; @@ -740,8 +765,10 @@ describe('Store', () => { emailAddress: contactEmail, firstName: contactFirstName, lastName: contactLastName, - phoneNumber: contactPhoneNumber, - optInSms: requestTextUpdates + homePhone: contactHomePhone, + servicePhone: contactServicePhone, + alternativePhone: contactAlternativePhone, + isSmsOptIn: requestTextUpdates }) }) })); @@ -1122,7 +1149,7 @@ describe('Store', () => { expect(store.order.customer.firstName).toBe(customer.firstName); expect(store.order.customer.lastName).toBe(customer.lastName); expect(store.order.customer.emailAddress).toBe(customer.emailAddress); - expect(store.order.customer.phoneNumber).toBe(customer.phoneNumber); + expect(store.order.contactInfo.homePhone).toBe(customer.phoneNumber); }); it('sets expected remaining order data', async () => { // Arrange @@ -2021,4 +2048,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); + }); + }); });