Fixing merge conflict

This commit is contained in:
Michaela Brydon 2024-03-08 11:00:32 -05:00
commit 6e4f35adab
14 changed files with 639 additions and 235 deletions

View file

@ -116,6 +116,10 @@ const endpoints = Object.freeze({
url: `${ACCOUNT_BASE_URL}/`, url: `${ACCOUNT_BASE_URL}/`,
method: 'GET' method: 'GET'
}, },
TaxOrderItems: {
url: `${PRICE_BASE_URL}/taxed-order-items`,
method: 'GET'
},
LogExperimentExposureIfAssigned: { LogExperimentExposureIfAssigned: {
url: `${EXPERIMENTS_BASE_URL}/log-exposure`, url: `${EXPERIMENTS_BASE_URL}/log-exposure`,
method: 'POST' method: 'POST'

View file

@ -23,7 +23,10 @@ export default {
return this.genericVehicleImage; return this.genericVehicleImage;
} }
const { imageUrl } = this.mainStore.order.vehicle; const imageUrl = (this.mainStore.hasSubmittedOrder())
? this.mainStore.submittedOrder.vehicle.imageUrl
: this.mainStore.order.vehicle.imageUrl;
if (!imageUrl || imageUrl === 'NULL') { if (!imageUrl || imageUrl === 'NULL') {
return this.getUnmatchedVehicleIcon(); return this.getUnmatchedVehicleIcon();
} }

View file

@ -136,7 +136,8 @@ describe('duplicateCheck.vue', () => {
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({ expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText, Text: duplicateOrderText,
Name: referralNumber, Name: referralNumber,
SubText: expectedSubtext SubText: expectedSubtext,
value: useMainStore().applicationUser.duplicateOrders[0]
}); });
}); });
test('duplicateOrder in store with null vehicle make => returns order with only date subtext', () => { test('duplicateOrder in store with null vehicle make => returns order with only date subtext', () => {
@ -173,7 +174,8 @@ describe('duplicateCheck.vue', () => {
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({ expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText, Text: duplicateOrderText,
Name: referralNumber, Name: referralNumber,
SubText: expectedSubtext SubText: expectedSubtext,
value: useMainStore().applicationUser.duplicateOrders[0]
}); });
}); });
test('duplicateOrder in store with null vehicle model => returns order with only date subtext', () => { test('duplicateOrder in store with null vehicle model => returns order with only date subtext', () => {
@ -210,7 +212,8 @@ describe('duplicateCheck.vue', () => {
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({ expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText, Text: duplicateOrderText,
Name: referralNumber, Name: referralNumber,
SubText: expectedSubtext SubText: expectedSubtext,
value: useMainStore().applicationUser.duplicateOrders[0]
}); });
}); });
test('duplicateOrder in store with all vehicle info => returns order with year, make, model and date in subtext', () => { test('duplicateOrder in store with all vehicle info => returns order with year, make, model and date in subtext', () => {
@ -248,7 +251,8 @@ describe('duplicateCheck.vue', () => {
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({ expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText, Text: duplicateOrderText,
Name: referralNumber, Name: referralNumber,
SubText: `${expectedVehicle}, ${expectedDate}` SubText: `${expectedVehicle}, ${expectedDate}`,
value: useMainStore().applicationUser.duplicateOrders[0]
}); });
}); });
}); });
@ -352,7 +356,7 @@ describe('duplicateCheck.vue', () => {
test('Selected duplicate => load session called', async () => { test('Selected duplicate => load session called', async () => {
// Arrange // Arrange
const newOrderSelectionName = getRandomString(6, 6); const newOrderSelectionName = getRandomString(6, 6);
const selectedAnswer = getRandomString(6, 6); const selectedAnswer = {};
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
router: { navigate: jest.fn() } router: { navigate: jest.fn() }
@ -405,7 +409,7 @@ describe('duplicateCheck.vue', () => {
test('Load session throws error => still navigate forward', async () => { test('Load session throws error => still navigate forward', async () => {
// Arrange // Arrange
const newOrderSelectionName = getRandomString(6, 6); const newOrderSelectionName = getRandomString(6, 6);
const selectedAnswer = getRandomString(6, 6); const selectedAnswer = {};
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
router: { navigate: jest.fn() } router: { navigate: jest.fn() }

View file

@ -75,7 +75,7 @@ export default {
}, },
data() { data() {
return { return {
selectedAnswer: '', selectedAnswer: null,
widget: { widget: {
siteHeader: 'SiteHeaderWidget', siteHeader: 'SiteHeaderWidget',
siteSubHeader: 'SiteSubHeaderWidget', siteSubHeader: 'SiteSubHeaderWidget',
@ -113,7 +113,8 @@ export default {
return { return {
Text: duplicateOrderText, Text: duplicateOrderText,
Name: o.referralNumber, Name: o.referralNumber,
SubText: toTitleCase(subtext) SubText: toTitleCase(subtext),
value: o
}; };
}) ?? []; }) ?? [];
}, },
@ -126,13 +127,16 @@ export default {
* @summary Steps to perform when forward button clicked. * @summary Steps to perform when forward button clicked.
*/ */
async forwardButtonAction() { async forwardButtonAction() {
if (this.selectedAnswer !== this.getNewOrderSelectionName) { if (this.selectedAnswer !== null && typeof this.selectedAnswer === 'object') {
await useMainStore().loadSession() await useMainStore().loadSession(this.selectedAnswer)
.then(() => {}, () => {}) .catch(() => {})
.finally(() => { this.navigateForward(); }); .finally(() => {
} else { this.navigateForward();
this.navigateForward(); });
return;
} }
this.navigateForward();
}, },
navigateForward() { navigateForward() {
if (!this.mainStore.order.policy.policyLookupSuccessful) { if (!this.mainStore.order.policy.policyLookupSuccessful) {

View file

@ -15,7 +15,7 @@ jest.mock('@/helpers/cms-content-helper', () => ({
fetchCmsContentForPage: jest.fn(), fetchCmsContentForPage: jest.fn(),
processIfStatements: jest.fn() processIfStatements: jest.fn()
})); }));
const wordingText = 'wording Text {custom:address}'; const wordingText = 'wording text {custom:address}';
const mockMixin = { const mockMixin = {
methods: { methods: {
@ -67,6 +67,55 @@ const initialStore = {
} }
}; };
const sessionStorage = {
schedule: {
date: '2024-03-01',
startTime: '09:00',
endTime: '10:00',
jobMinMinutes: 60,
jobMaxMinutes: 90
},
serviceLocation: {
address: '123 Test Way',
address2: '#1',
city: 'Mesa',
state: 'AZ',
zipCode: '12345',
appointmentType: 'Inshop',
provider: {
address: {
streetAddress: '123 Safelite Street',
city: 'Mesa',
state: 'AZ',
zipCode: '12345'
}
}
}
};
const sessionStorageMock = (() => {
let sessionStore = {};
return {
getItem(key) {
return sessionStore[key] || null;
},
setItem(key, value) {
sessionStore[key] = value.toString();
},
removeItem(key) {
delete sessionStore[key];
},
clear() {
sessionStore = {};
}
};
})();
Object.defineProperty(window, 'sessionStorage', {
value: sessionStorageMock
});
function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) { function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) {
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
router: { router: {
@ -107,9 +156,16 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
} }
describe('OrderConfirmation.vue', () => { describe('OrderConfirmation.vue', () => {
beforeEach(() => {
window.sessionStorage.clear();
});
afterEach(() => {
window.sessionStorage.removeItem('submittedOrder');
});
describe('Rendering', () => { describe('Rendering', () => {
test('Should render Site Header', () => { test('Should render Site Header', () => {
// Arrange // Arrange
window.sessionStorage.setItem('submittedOrder', JSON.stringify(sessionStorage));
const { wrapper } = getMountedComponent(initialStore); const { wrapper } = getMountedComponent(initialStore);
// Act // Act
@ -120,6 +176,7 @@ describe('OrderConfirmation.vue', () => {
}); });
test('Should render Vehicle Banner', () => { test('Should render Vehicle Banner', () => {
// Arrange // Arrange
window.sessionStorage.setItem('submittedOrder', JSON.stringify(sessionStorage));
const { wrapper } = getMountedComponent(initialStore); const { wrapper } = getMountedComponent(initialStore);
// Act // Act
@ -130,6 +187,7 @@ describe('OrderConfirmation.vue', () => {
}); });
test('If Advanced flow, should display Site Footer', () => { test('If Advanced flow, should display Site Footer', () => {
// Arrange // Arrange
window.sessionStorage.setItem('submittedOrder', JSON.stringify(sessionStorage));
const testStore = { const testStore = {
order: { order: {
schedule: { schedule: {
@ -154,6 +212,7 @@ describe('OrderConfirmation.vue', () => {
}); });
test('If Essential flow, should not display Site Footer', () => { test('If Essential flow, should not display Site Footer', () => {
// Arrange // Arrange
window.sessionStorage.setItem('submittedOrder', JSON.stringify(sessionStorage));
const { wrapper } = getMountedComponent(initialStore); const { wrapper } = getMountedComponent(initialStore);
// Act // Act
@ -166,6 +225,7 @@ describe('OrderConfirmation.vue', () => {
describe('Navigation', () => { describe('Navigation', () => {
test('If Advanced flow, forward button action navigates to carrier URL', () => { test('If Advanced flow, forward button action navigates to carrier URL', () => {
// Arrange // Arrange
window.sessionStorage.setItem('submittedOrder', JSON.stringify(sessionStorage));
const carrierReturnUrl = 'testURL'; const carrierReturnUrl = 'testURL';
const testStore = { const testStore = {
order: { order: {
@ -193,6 +253,7 @@ describe('OrderConfirmation.vue', () => {
describe('Computed properties', () => { describe('Computed properties', () => {
test('appointmentDateFormatted should return date in expected format', () => { test('appointmentDateFormatted should return date in expected format', () => {
// Arrange // Arrange
window.sessionStorage.setItem('submittedOrder', JSON.stringify(sessionStorage));
const { wrapper } = getMountedComponent(initialStore); const { wrapper } = getMountedComponent(initialStore);
// Act // Act
@ -203,19 +264,18 @@ describe('OrderConfirmation.vue', () => {
}); });
test('appointmentTimeFormatted should return Mobile time in expected format', () => { test('appointmentTimeFormatted should return Mobile time in expected format', () => {
// Arrange // Arrange
const testStore = { const testSessionStorage = {
order: { schedule: {
schedule: { date: '2019-01-01',
date: '2019-01-01', startTime: '09:00',
startTime: '09:00', endTime: '10:00'
endTime: '10:00' },
}, serviceLocation: {
serviceLocation: { appointmentType: 'Mobile'
appointmentType: 'Mobile'
}
} }
}; };
const { wrapper } = getMountedComponent(testStore); window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.appointmentTimeFormatted; const testValue = wrapper.vm.appointmentTimeFormatted;
@ -225,19 +285,26 @@ describe('OrderConfirmation.vue', () => {
}); });
test('appointmentTimeFormatted should return Drop Off time in expected format', () => { test('appointmentTimeFormatted should return Drop Off time in expected format', () => {
// Arrange // Arrange
const testStore = { const testSessionStorage = {
order: { schedule: {
schedule: { date: '2019-01-01',
date: '2019-01-01', startTime: '09:00',
startTime: '09:00', endTime: '10:00'
endTime: '10:00' },
}, serviceLocation: {
serviceLocation: { appointmentType: 'Dropoff',
appointmentType: 'Dropoff' provider: {
address: {
streetAddress: '123 Safelite Street',
city: 'Mesa',
state: 'AZ',
zipCode: '12345'
}
} }
} }
}; };
const { wrapper } = getMountedComponent(testStore); window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.appointmentTimeFormatted; const testValue = wrapper.vm.appointmentTimeFormatted;
@ -247,6 +314,7 @@ describe('OrderConfirmation.vue', () => {
}); });
test('appointmentTimeFormatted should return In Shop time in expected format', () => { test('appointmentTimeFormatted should return In Shop time in expected format', () => {
// Arrange // Arrange
window.sessionStorage.setItem('submittedOrder', JSON.stringify(sessionStorage));
const { wrapper } = getMountedComponent(initialStore); const { wrapper } = getMountedComponent(initialStore);
// Act // Act
@ -257,111 +325,162 @@ describe('OrderConfirmation.vue', () => {
}); });
test('appointmentWordingText should return Mobile text in expected format', () => { test('appointmentWordingText should return Mobile text in expected format', () => {
// Arrange // Arrange
const testStore = { const testSessionStorage = {
order: { schedule: {
schedule: { date: '2019-01-01',
date: '2019-01-01', startTime: '09:00',
startTime: '09:00', endTime: '10:00'
endTime: '10:00' },
}, serviceLocation: {
serviceLocation: { address: '123 Test Way',
address: '123 Test Way', address2: '#1',
address2: '#1', city: 'Mesa',
city: 'Mesa', state: 'AZ',
state: 'AZ', zipCode: '12345',
zipCode: '12345', appointmentType: 'Mobile'
appointmentType: 'Mobile'
}
} }
}; };
const { wrapper } = getMountedComponent(testStore); window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.appointmentWordingText; const testValue = wrapper.vm.appointmentWordingText;
// Assert // Assert
expect(testValue).toEqual('wording Text <br/>123 Test Way, #1,<br/> Mesa, AZ 12345<br/>'); expect(testValue).toEqual('wording text 123 Test Way, #1,<br/> Mesa, AZ 12345');
}); });
test('appointmentWordingText should return Drop Off text in expected format', () => { test('appointmentWordingText should return Drop Off text in expected format', () => {
// Arrange // Arrange
const testStore = { const testSessionStorage = {
order: { schedule: {
schedule: { date: '2019-01-01',
date: '2019-01-01', startTime: '09:00',
startTime: '09:00', endTime: '10:00'
endTime: '10:00' },
serviceLocation: {
provider: {
address: {
streetAddress: '123 Safelite Street',
city: 'Mesa',
state: 'AZ',
zipCode: '12345'
}
}, },
serviceLocation: { appointmentType: 'Dropoff'
provider: {
address: {
streetAddress: '123 Safelite Street',
city: 'Mesa',
state: 'AZ',
zipCode: '12345'
}
},
appointmentType: 'Dropoff'
}
} }
}; };
const { wrapper } = getMountedComponent(testStore); window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.appointmentWordingText; const testValue = wrapper.vm.appointmentWordingText;
// Assert // Assert
expect(testValue).toEqual('wording Text <br/>123 Safelite Street,<br/> Mesa, AZ 12345<br/>'); expect(testValue).toEqual('wording text 123 Safelite Street,<br/> Mesa, AZ 12345');
}); });
test('appointmentWordingText should return In Shop text in expected format', () => { test('appointmentWordingText should return In Shop text in expected format', () => {
// Arrange // Arrange
const { wrapper } = getMountedComponent(initialStore); const testSessionStorage = {
schedule: {
date: '2019-01-01',
startTime: '09:00',
endTime: '10:00'
},
serviceLocation: {
provider: {
address: {
streetAddress: '123 Safelite Street',
city: 'Mesa',
state: 'AZ',
zipCode: '12345'
}
},
appointmentType: 'Inshop'
}
};
window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.appointmentWordingText; const testValue = wrapper.vm.appointmentWordingText;
// Assert // Assert
expect(testValue).toEqual('wording Text <br/>123 Safelite Street,<br/> Mesa, AZ 12345<br/>'); expect(testValue).toEqual('wording text 123 Safelite Street,<br/> Mesa, AZ 12345');
}); });
test('serviceLocationFullAddress should return text in expected format', () => { test('serviceLocationFullAddress should return text in expected format', () => {
// Arrange // Arrange
const { wrapper } = getMountedComponent(initialStore); const testSessionStorage = {
schedule: {
date: '2019-01-01',
startTime: '09:00',
endTime: '10:00'
},
serviceLocation: {
address: '123 Test Way',
address2: '#1',
city: 'Mesa',
state: 'AZ',
zipCode: '12345',
appointmentType: 'Mobile'
}
};
window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.serviceLocationFullAddress; const testValue = wrapper.vm.serviceLocationFullAddress;
// Assert // Assert
expect(testValue).toEqual('<br/>123 Test Way, #1,<br/> Mesa, AZ 12345<br/>'); expect(testValue).toEqual('123 Test Way, #1,<br/> Mesa, AZ 12345');
}); });
test('providerFullAddress should return text in expected format', () => { test('providerFullAddress should return text in expected format', () => {
// Arrange // Arrange
const { wrapper } = getMountedComponent(initialStore); const testSessionStorage = {
schedule: {
date: '2019-01-01',
startTime: '09:00',
endTime: '10:00'
},
serviceLocation: {
provider: {
address: {
streetAddress: '123 Safelite Street',
city: 'Mesa',
state: 'AZ',
zipCode: '12345'
}
},
appointmentType: 'Inshop'
}
};
window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.providerFullAddress; const testValue = wrapper.vm.providerFullAddress;
// Assert // Assert
expect(testValue).toEqual('<br/>123 Safelite Street,<br/> Mesa, AZ 12345<br/>'); expect(testValue).toEqual('123 Safelite Street,<br/> Mesa, AZ 12345');
}); });
test('appointmentWordingText2 should return Mobile text in expected format', () => { test('appointmentWordingText2 should return Mobile text in expected format', () => {
// Arrange // Arrange
const testStore = { const testSessionStorage = {
order: { schedule: {
schedule: { date: '2019-01-01',
date: '2019-01-01', startTime: '09:00',
startTime: '09:00', endTime: '10:00'
endTime: '10:00' },
}, serviceLocation: {
serviceLocation: { address: '123 Test Way',
address: '123 Test Way', address2: '#1',
address2: '#1', city: 'Mesa',
city: 'Mesa', state: 'AZ',
state: 'AZ', zipCode: '12345',
zipCode: '12345', appointmentType: 'Mobile'
appointmentType: 'Mobile'
}
} }
}; };
const { wrapper } = getMountedComponent(testStore); window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.appointmentWordingText2; const testValue = wrapper.vm.appointmentWordingText2;
@ -371,27 +490,26 @@ describe('OrderConfirmation.vue', () => {
}); });
test('appointmentWordingText2 should return Drop Off and text in expected format', () => { test('appointmentWordingText2 should return Drop Off and text in expected format', () => {
// Arrange // Arrange
const testStore = { const testSessionStorage = {
order: { schedule: {
schedule: { date: '2019-01-01',
date: '2019-01-01', startTime: '09:00',
startTime: '09:00', endTime: '10:00'
endTime: '10:00' },
serviceLocation: {
provider: {
address: {
streetAddress: '123 Safelite Street',
city: 'Mesa',
state: 'AZ',
zipCode: '12345'
}
}, },
serviceLocation: { appointmentType: 'Dropoff'
provider: {
address: {
streetAddress: '123 Safelite Street',
city: 'Mesa',
state: 'AZ',
zipCode: '12345'
}
},
appointmentType: 'Dropoff'
}
} }
}; };
const { wrapper } = getMountedComponent(testStore); window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.appointmentWordingText2; const testValue = wrapper.vm.appointmentWordingText2;
@ -402,7 +520,26 @@ describe('OrderConfirmation.vue', () => {
}); });
test('appointmentWordingText2 should return In Shop text in expected format', () => { test('appointmentWordingText2 should return In Shop text in expected format', () => {
// Arrange // Arrange
const { wrapper } = getMountedComponent(initialStore); const testSessionStorage = {
schedule: {
date: '2019-01-01',
startTime: '09:00',
endTime: '10:00'
},
serviceLocation: {
provider: {
address: {
streetAddress: '123 Safelite Street',
city: 'Mesa',
state: 'AZ',
zipCode: '12345'
}
},
appointmentType: 'Inshop'
}
};
window.sessionStorage.setItem('submittedOrder', JSON.stringify(testSessionStorage));
const { wrapper } = getMountedComponent();
// Act // Act
const testValue = wrapper.vm.appointmentWordingText2; const testValue = wrapper.vm.appointmentWordingText2;

View file

@ -58,7 +58,9 @@ import settleAllPromises from '@/helpers/layout-helper';
import { Form } from 'vee-validate'; import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { get12HourTimeFormat, get12HourTimeMobileFormat, convertDateStringToDate, import { get12HourTimeFormat,
get12HourTimeMobileFormat,
convertDateStringToDate,
getDisplayTextForDurationLength } from '@/helpers/date-helper.js'; getDisplayTextForDurationLength } from '@/helpers/date-helper.js';
import { toTitleCase } from '@/helpers/text-helper.js'; import { toTitleCase } from '@/helpers/text-helper.js';
import { AppointmentTypeStrings } from '@/constants/schedule-constants'; import { AppointmentTypeStrings } from '@/constants/schedule-constants';
@ -66,14 +68,15 @@ import { AppointmentTypeStrings } from '@/constants/schedule-constants';
export default { export default {
name: 'order-confirmation', name: 'order-confirmation',
components: { components: {
// eslint-disable-next-line vue/no-reserved-component-names
Form,
siteHeader, siteHeader,
vehicleBanner, vehicleBanner,
siteFooter, siteFooter
// eslint-disable-next-line vue/no-reserved-component-names
Form
}, },
mixins: [BaseFormMixin], mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
useMainStore().createSubmittedOrder();
// Call APIs // Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage); const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results // Settle promises and get results
@ -90,7 +93,8 @@ export default {
}, },
setup() { setup() {
const mainStore = useMainStore(); const mainStore = useMainStore();
return { mainStore }; const { submittedOrder } = mainStore;
return { mainStore, submittedOrder };
}, },
computed: { computed: {
carrierName() { carrierName() {
@ -106,16 +110,16 @@ export default {
return this.getCmsContent('OrderConfirmationContent', 'Image'); return this.getCmsContent('OrderConfirmationContent', 'Image');
}, },
appointmentType() { appointmentType() {
return this.mainStore.order.serviceLocation.appointmentType; return this.submittedOrder.serviceLocation.appointmentType;
}, },
appointmentDate() { appointmentDate() {
return this.mainStore.order.schedule.date; return this.submittedOrder.schedule.date;
}, },
appointmentStartTime() { appointmentStartTime() {
return this.mainStore.order.schedule.startTime; return this.submittedOrder.schedule.startTime;
}, },
appointmentEndTime() { appointmentEndTime() {
return this.mainStore.order.schedule.endTime; return this.submittedOrder.schedule.endTime;
}, },
appointmentDateFormatted() { appointmentDateFormatted() {
// This conversion ensures we don't get get GMT induced date changes // This conversion ensures we don't get get GMT induced date changes
@ -144,39 +148,39 @@ export default {
return this.getBodyText2FromCms('DropOffAndInShopWordingWidget'); return this.getBodyText2FromCms('DropOffAndInShopWordingWidget');
}, },
serviceLocationAddress() { serviceLocationAddress() {
return this.mainStore.order.serviceLocation.address; return this.submittedOrder.serviceLocation.address;
}, },
serviceLocationAddress2() { serviceLocationAddress2() {
return this.mainStore.order.serviceLocation.address2; return this.submittedOrder.serviceLocation.address2;
}, },
serviceLocationCity() { serviceLocationCity() {
return this.mainStore.order.serviceLocation.city; return this.submittedOrder.serviceLocation.city;
}, },
serviceLocationState() { serviceLocationState() {
return this.mainStore.order.serviceLocation.state; return this.submittedOrder.serviceLocation.state;
}, },
serviceLocationZipCode() { serviceLocationZipCode() {
return this.mainStore.order.serviceLocation.zipCode; return this.submittedOrder.serviceLocation.zipCode;
}, },
serviceLocationFullAddress() { serviceLocationFullAddress() {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
return `<br/>${this.serviceLocationAddress}, ${this.serviceLocationAddress2 ? `${this.serviceLocationAddress2},` : ''}<br/> ${this.serviceLocationCity}, ${this.serviceLocationState} ${this.serviceLocationZipCode}<br/>`; return `${this.serviceLocationAddress}, ${this.serviceLocationAddress2 ? `${this.serviceLocationAddress2},` : ''}<br/> ${this.serviceLocationCity}, ${this.serviceLocationState} ${this.serviceLocationZipCode}`;
}, },
providerAddress() { providerAddress() {
return toTitleCase(this.mainStore.order.serviceLocation.provider.address.streetAddress); return toTitleCase(this.submittedOrder.serviceLocation.provider.address.streetAddress);
}, },
providerCity() { providerCity() {
return toTitleCase(this.mainStore.order.serviceLocation.provider.address.city); return toTitleCase(this.submittedOrder.serviceLocation.provider.address.city);
}, },
providerState() { providerState() {
return this.mainStore.order.serviceLocation.provider.address.state; return this.submittedOrder.serviceLocation.provider.address.state;
}, },
providerZipCode() { providerZipCode() {
return this.mainStore.order.serviceLocation.provider.address.zipCode; return this.submittedOrder.serviceLocation.provider.address.zipCode;
}, },
providerFullAddress() { providerFullAddress() {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
return `<br/>${this.providerAddress},<br/> ${this.providerCity}, ${this.providerState} ${this.providerZipCode}<br/>`; return `${this.providerAddress},<br/> ${this.providerCity}, ${this.providerState} ${this.providerZipCode}`;
}, },
appointmentWordingText() { appointmentWordingText() {
switch (this.appointmentType) { switch (this.appointmentType) {
@ -217,18 +221,19 @@ export default {
} }
}, },
mobileAppointment() { mobileAppointment() {
return this.mainStore.isMobileAppointment; return this.submittedOrder.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|| this.submittedOrder.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP;
}, },
inShopAppointment() { inShopAppointment() {
return this.mainStore.isInShopAppointment; return this.submittedOrder.serviceLocation.appointmentType === AppointmentTypeStrings.IN_SHOP;
}, },
dropOffAppointment() { dropOffAppointment() {
return this.mainStore.isDropOffAppointment; return this.submittedOrder.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF;
}, },
inShopAppointmentDuration() { inShopAppointmentDuration() {
const inshopDurationTime = getDisplayTextForDurationLength( const inshopDurationTime = getDisplayTextForDurationLength(
this.mainStore.order.schedule.jobMinMinutes, this.submittedOrder.schedule.jobMinMinutes,
this.mainStore.order.schedule.jobMaxMinutes this.submittedOrder.schedule.jobMaxMinutes
); );
return inshopDurationTime; return inshopDurationTime;
} }
@ -310,6 +315,9 @@ $page-side-padding: 1.5rem;
} }
.appointment-text { .appointment-text {
:deep(p) {
margin: 0;
}
:deep(strong) { :deep(strong) {
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
color: $black; color: $black;

View file

@ -33,7 +33,6 @@
ref="siteFooter" ref="siteFooter"
cmsWidgetName="SiteFooterWidget" cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
:isBackButtonHidden="shouldHideBackButton"
:isStackedVertically="true" :isStackedVertically="true"
@backClicked="navigateBack" @backClicked="navigateBack"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />

View file

@ -264,44 +264,6 @@ describe('payment-page.vue', () => {
}); });
}); });
describe('beforeRouteEnter', () => {
test('Properly initializes fields and kicks off hop', async () => {
// Arrange
const vmMock = {
setCmsContent: jest.fn(),
$refs: {
cart: {
cartItems: []
}
},
getPiaLineItems: jest.fn(),
fetchSignatureInfo: jest.fn(),
setIFrameListener: jest.fn(),
$nextTick: (f) => {
f();
}
};
const nextF = (f) => {
f(vmMock);
};
// Act
await payment.beforeRouteEnter.call(
vmMock,
{ query: { issPage: 'payment-page' } },
undefined,
nextF
);
// Assert
expect(vmMock.setCmsContent).toBeCalled();
expect(vmMock.fetchSignatureInfo).toBeCalled();
expect(vmMock.setIFrameListener).toBeCalled();
});
});
describe('payment type mapping', () => { describe('payment type mapping', () => {
describe('getPaymentType', () => { describe('getPaymentType', () => {
test('Maps AFTERPAY -> hopPaymentMethods.AFTERPAY', () => { test('Maps AFTERPAY -> hopPaymentMethods.AFTERPAY', () => {

View file

@ -1,9 +1,5 @@
<template> <template>
<Form <Form>
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="page-container-grouped-styles"> <div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative"> <div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" /> <siteHeader cmsWidgetName="SiteHeaderWidget" />
@ -21,12 +17,12 @@
</div> </div>
<siteFooter <siteFooter
ref="siteFooter" ref="siteFooter"
cmsWidgetName="SiteFooterWidget" cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="true" :isForwardActionDisabled="true"
:isForwardButtonHidden="true" :isForwardButtonHidden="true"
@ForwardClicked="forwardButtonAction" @ForwardClicked="forwardButtonAction"
@backClicked="backButtonAction" /> @backClicked="backButtonAction" />
</div> </div>
</div> </div>
@ -367,6 +363,7 @@ import issPageValues from '@/router/router-constants/issPage-values.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper'; import settleAllPromises from '@/helpers/layout-helper';
import { Form } from 'vee-validate'; import { Form } from 'vee-validate';
import baseMixin from '@/mixins/base-mixin.js';
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import iframeResize from 'iframe-resizer/js/iframeResizer.js'; import iframeResize from 'iframe-resizer/js/iframeResizer.js';
@ -402,6 +399,9 @@ export default {
const paymentSignaturePromise = await useMainStore().getPaymentSignature(); const paymentSignaturePromise = await useMainStore().getPaymentSignature();
const wipersPromise = useMainStore().getWipers();
const rainDefensePromise = useMainStore().getRainDefense();
// Settle promises and get results // Settle promises and get results
const promiseResultMap = [ const promiseResultMap = [
{ {
@ -411,16 +411,50 @@ export default {
{ {
resultKey: 'paymentSignature', resultKey: 'paymentSignature',
promise: paymentSignaturePromise promise: paymentSignaturePromise
},
{
resultKey: 'wipers',
promise: wipersPromise
},
{
resultKey: 'rainDefense',
promise: rainDefensePromise
} }
]; ];
// use resultMap to populate layout content. // use resultMap to populate layout content.
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
const lineItemsFromStore = useMainStore().lineItems;
const glassParts = lineItemsFromStore.glassParts ?? [];
const supportingItems = lineItemsFromStore.supportingItems ?? [];
const lineItemsToTax = [
resultMap.rainDefense,
...supportingItems,
...resultMap.wipers,
...glassParts
];
const availableVaps = [resultMap.rainDefense, ...resultMap.wipers];
const pricedLineItemsToTax = await useMainStore().priceOrderItemsAndSaveServerData(lineItemsToTax);
const taxedLineItems = await useMainStore().taxOrderItemsAndSaveServerData(pricedLineItemsToTax);
// Match all line items to the line items as they are in the store
// and rebuild the original structure.
const taxLineItems = useMainStore().mapTaxedLineItemsToStoreFormat(taxedLineItems, lineItemsFromStore);
const taxedVaps = useMainStore().mapTaxedLineItemsToStoreFormat(taxedLineItems, availableVaps);
next((vm) => { next((vm) => {
vm.setCmsContent(resultMap.cmsContent); vm.setCmsContent(resultMap.cmsContent);
vm.setData(taxedVaps, taxLineItems);
vm.$nextTick(() => { vm.$nextTick(() => {
if (vm.$refs.cart) {
const { cartItems } = vm.$refs.cart;
vm.getPayInAdvanceLineItems(cartItems);
} else {
vm.getMockPiaLineItems();
}
vm.fetchSignatureInfo(resultMap.paymentSignature); vm.fetchSignatureInfo(resultMap.paymentSignature);
vm.setIFrameListener(); vm.setIFrameListener();
}); });
@ -460,11 +494,11 @@ export default {
computed: { computed: {
payInAdvanceResponseUrl() { payInAdvanceResponseUrl() {
const { protocol, host } = window.location; const { protocol, host } = window.location;
return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_RETURN}&src=iss-nextgen`; return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_RETURN}&src=concept-funnel`;
}, },
payInAdvanceCancelUrl() { payInAdvanceCancelUrl() {
const { protocol, host } = window.location; const { protocol, host } = window.location;
return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_METHOD}&src=iss-nextgen`; return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_METHOD}&src=concept-funnel`;
}, },
dynamicCSSUrl() { dynamicCSSUrl() {
const { protocol, hostname, port } = window.location; const { protocol, hostname, port } = window.location;
@ -553,6 +587,10 @@ export default {
&& paymentMethodReqs && paymentMethodReqs
); );
}, },
setData(taxedVaps, taxLineItems) {
this.availableVaps = taxedVaps;
this.lineItems = taxLineItems;
},
getWorkOrderNumber() { getWorkOrderNumber() {
const { workOrderNumber } = useMainStore().order; const { workOrderNumber } = useMainStore().order;
if (workOrderNumber) { if (workOrderNumber) {
@ -597,11 +635,31 @@ export default {
return useMainStore().payment.payInAdvanceType; return useMainStore().payment.payInAdvanceType;
} }
}, },
getPayInAdvanceLineItems(cartItems) {
const { glassParts } = useMainStore().order.lineItems;
const lineItems = (glassParts === null) ? ['Labor|0|1', 'Repair supplies|0|1'] : ['Parts and labor|0|1'];
cartItems.forEach((item) => {
if (item.name !== null && item.category !== 'promos') {
lineItems.push(`${item.name}|${(item.salesTax + item.subTotal).toFixed(2)}|1`);
}
});
this.payInAdvanceLineItems = lineItems.join('||');
},
getMockPiaLineItems() {
let lineItems = [];
lineItems = ['Parts and labor|0|1'];
lineItems.push('New wiper blades|75.22|1');
lineItems.push('Recycling|37.60|1');
this.payInAdvanceLineItems = lineItems.join('||');
},
getAmountDue() { getAmountDue() {
return 0; return baseMixin.methods.getAmountDue(useMainStore().lineItems);
}, },
getDisplayAmountDue() { getDisplayAmountDue() {
return 0; return baseMixin.methods.getDisplayAmountDue(useMainStore().lineItems);
}, },
fetchSignatureInfo(signatureInfo) { fetchSignatureInfo(signatureInfo) {
this.authToken = signatureInfo.token; this.authToken = signatureInfo.token;

View file

@ -36,6 +36,58 @@ export default {
savePageDataToStore(page, data) { savePageDataToStore(page, data) {
useMainStore().updatePageData({ page, data }); useMainStore().updatePageData({ page, data });
}, },
getTotalPriceOfAllLineItemsAndChildParts(lineItems, includeTax) {
let totalPrice = 0;
lineItems.forEach((lineItem) => {
totalPrice += this.getTotalLineItemPrice(lineItem, includeTax);
if (lineItem.childParts) {
totalPrice += this.getTotalPriceOfAllLineItemsAndChildParts(
lineItem.childParts,
includeTax
);
}
});
return totalPrice;
},
getTotalLineItemPrice(lineItem, includeTax) {
if (includeTax) {
return (
lineItem.kitPrice
+ lineItem.laborAmount
+ lineItem.sellingPrice
+ lineItem.salesTax
);
}
return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice;
},
getDisplayAmountDue(lineItems) {
return this.getAmountDue(lineItems).toLocaleString('en-US', {
style: 'currency',
currency: 'USD'
});
},
getAmountDue(lineItems) {
let amountDue = 0;
if (lineItems.glassParts) {
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
lineItems.glassParts,
false
);
}
if (lineItems.supportingItems) {
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
lineItems.supportingItems,
false
);
}
if (lineItems.vaps) {
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(lineItems.vaps, false);
}
if (lineItems.promos) {
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(lineItems.promos, false);
}
return ((amountDue * 100) / 100).toFixed(2);
},
scrollToPageTop() { scrollToPageTop() {
const container = document.getElementsByClassName('page-container-grouped-styles')[0]; const container = document.getElementsByClassName('page-container-grouped-styles')[0];
container.scrollTo({ top: 0, left: 0, behavior: 'smooth' }); container.scrollTo({ top: 0, left: 0, behavior: 'smooth' });

View file

@ -46,6 +46,13 @@ const routes = [
await runExperiments(issPageToUse); // fmg has this further down await runExperiments(issPageToUse); // fmg has this further down
} }
// Intercept all navigation if a submitted order exists in storage
if (useMainStore().hasSubmittedOrder()) {
if (to.query.issPage !== issPageValues.ENTRY_PAGE) {
return await GoToOrderConfirmationPage(next);
}
}
// If the saved session has timed out, clear the session, execute 404 logic. // If the saved session has timed out, clear the session, execute 404 logic.
if (getISSCookie() !== null && !isSavedSessionStillActive()) { if (getISSCookie() !== null && !isSavedSessionStillActive()) {
// await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE); // await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
@ -127,8 +134,16 @@ router.beforeEach(async (to, from) => {
showIssLoadingModal(true); showIssLoadingModal(true);
} }
const toQueryPage = to.query?.issPage;
const notToPayInAdvanceReturn = toQueryPage !== issPageValues.PAYMENT_RETURN;
const isInIframe = fromQueryPage === issPageValues.PAYMENT_PAGE; const isInIframe = fromQueryPage === issPageValues.PAYMENT_PAGE;
if (isInIframe) {
// isFromPaymentPageToOrderConfirmation workaround for navigating from an iframe but
// isInIframe evaluates to false for some reason when navigating from payment to confirmation
const isFromPaymentPageToOrderConfirmation =
fromQueryPage === issPageValues.PAYMENT_PAGE && toQueryPage === issPageValues.ORDER_CONFIRMATION;
if ((isInIframe && notToPayInAdvanceReturn) || isFromPaymentPageToOrderConfirmation) {
// need to set window.top.location.href directly when navigating out of an iframe // need to set window.top.location.href directly when navigating out of an iframe
// especially when navigating with browser buttons // especially when navigating with browser buttons
const newUrl = `${window.top.location.origin}${to.href}`; const newUrl = `${window.top.location.origin}${to.href}`;
@ -347,6 +362,20 @@ async function GoToAccessIsDenied(next) {
}); });
} }
async function GoToOrderConfirmationPage(next) {
const nextPageName = issPageValues.ORDER_CONFIRMATION;
router.addRoute({
path: '/',
name: nextPageName,
component: lazyLoadComponent(nextPageName)
});
next({
name: nextPageName,
query: { issPage: nextPageName }
});
}
async function GoToStartOn404(next, msgCopy = null, msgHeadline = null) { async function GoToStartOn404(next, msgCopy = null, msgHeadline = null) {
const errorPageName = issPageValues.WELCOME_PAGE; const errorPageName = issPageValues.WELCOME_PAGE;
router.addRoute({ router.addRoute({

View file

@ -654,7 +654,7 @@ const routingTable = () => [
}, },
{ {
scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS, scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS,
destinationIssPageValue: issPageValues.CONFIRMATION destinationIssPageValue: issPageValues.ORDER_CONFIRMATION
} }
] ]
}, },

View file

@ -12,6 +12,7 @@ import issPageValues from '@/router/router-constants/issPage-values';
import damageLocationsSelected from '@/constants/damage-locations-selected'; import damageLocationsSelected from '@/constants/damage-locations-selected';
import coverageStatuses from '@/constants/coverage-statuses'; import coverageStatuses from '@/constants/coverage-statuses';
import { AppointmentTypeStrings } from '@/constants/schedule-constants'; import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import { deepClone } from '@/helpers/object-helper';
import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper'; import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper';
import { paymentMethods } from '@/constants/payment-method-constants'; import { paymentMethods } from '@/constants/payment-method-constants';
import webStorageConstants from '@/constants/web-storage-constants'; import webStorageConstants from '@/constants/web-storage-constants';
@ -371,7 +372,8 @@ export const useMainStore = defineStore({
}), }),
experimentSettings: (state) => state.applicationUser.experiments experimentSettings: (state) => state.applicationUser.experiments
.map((x) => x.settings) .map((x) => x.settings)
.reduce((r, c) => Object.assign(r, c), {}) ?? {} .reduce((r, c) => Object.assign(r, c), {}) ?? {},
submittedOrder: () => JSON.parse(window.sessionStorage.getItem('submittedOrder'))
}, },
actions: actions:
{ {
@ -900,10 +902,8 @@ export const useMainStore = defineStore({
}, },
async getWipers() { async getWipers() {
const { carId } = this.order.vehicle; const { carId } = this.order.vehicle;
// WARNING const serviceZipCode = this.order.serviceLocation.zipCode;
// TODO: this is temp test code until serviceLocation is complete.
// const serviceZipCode = this.order.serviceLocation.zipCode;
const serviceZipCode = '44902';
return globalMethods return globalMethods
.callHttpClient({ .callHttpClient({
method: endpoints.GetWipers.method, method: endpoints.GetWipers.method,
@ -1047,7 +1047,68 @@ export const useMainStore = defineStore({
endpoint: `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&${lineItems}&${glassPieces}` endpoint: `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&${lineItems}&${glassPieces}`
}); });
}, },
mapTaxedLineItemsToStoreFormat(availableLineItems, storeLineItems) {
// clone the lineItems array because what we're passing in is referencing the store directly
const lineItems = deepClone(storeLineItems);
// eslint-disable-next-line no-restricted-syntax, prefer-const
for (let [category, lineItemsInCategory] of Object.entries(lineItems)) {
lineItemsInCategory = lineItemsInCategory ?? [];
if (category === 'supportingItems') {
// if the category is supporting items we need to filter out the items that aren't repair chips
const nonRepairChipSupportItemsLineItems = lineItemsInCategory.filter((lineItem) => lineItem.partNumber !== 'WSREPAIR');
/*
Because repair chips all have the same part number but different prices based on the quantity,
we have to sort the store line items and available line items by descending labor amount in order to
map the tax correctly to each repair chip
*/
// get the supporting items that ARE repair chips and sort them by descending labor amount
let repairChipLineItems = lineItemsInCategory.filter((lineItem) => lineItem.partNumber === 'WSREPAIR');
repairChipLineItems = repairChipLineItems.sort((a, b) => parseFloat(b.laborAmount) - parseFloat(a.laborAmount));
// get the supporting items from the available line items (taxed) that ARE repair chips and sort them by descending labor amount
let availableRepairChipLineItems = availableLineItems.filter((lineItem) => lineItem.partNumber === 'WSREPAIR');
availableRepairChipLineItems = availableRepairChipLineItems.sort((a, b) => parseFloat(b.laborAmount) - parseFloat(a.laborAmount));
// go through each one of those mapping the taxes to the correct chip
for (let i = 0; i < availableRepairChipLineItems.length; i++) {
repairChipLineItems[i].salesTax = availableRepairChipLineItems[i].salesTax;
}
// then we map the non-repair chip items based on part number
for (
let lineItemIndex = 0;
lineItemIndex < nonRepairChipSupportItemsLineItems.length;
lineItemIndex++
) {
const availableLineItem = availableLineItems.find((ali) =>
ali.partNumber === nonRepairChipSupportItemsLineItems[lineItemIndex].partNumber);
if (availableLineItem) {
nonRepairChipSupportItemsLineItems[lineItemIndex].salesTax =
availableLineItem.salesTax;
}
}
// finally we splice the two arrays back into one
lineItemsInCategory = nonRepairChipSupportItemsLineItems.concat(repairChipLineItems);
} else {
for (
let lineItemIndex = 0;
lineItemIndex < lineItemsInCategory.length;
lineItemIndex++
) {
const availableLineItem = availableLineItems.find((ali) => ali.partNumber === lineItemsInCategory[lineItemIndex].partNumber);
if (availableLineItem) {
lineItemsInCategory[lineItemIndex].salesTax = availableLineItem.salesTax;
}
}
}
}
return lineItems;
},
lookupVehicleByVin(vin) { lookupVehicleByVin(vin) {
return globalMethods.callHttpClient({ return globalMethods.callHttpClient({
method: endpoints.LookupVehicleByVin.method, method: endpoints.LookupVehicleByVin.method,
@ -1224,20 +1285,17 @@ export const useMainStore = defineStore({
}); });
}, },
async loadSession() { async loadSession(duplicate) {
const { applicationUser, order, issConfig } = this; const { applicationUser, order, issConfig } = this;
// TODO how to get savedSessionId for a duplicate referral?
try { try {
const response = await globalMethods.callHttpClient({ const response = await globalMethods.callHttpClient({
method: endpoints.LoadSession.method, method: endpoints.LoadSession.method,
endpoint: endpoints.LoadSession.url, endpoint: endpoints.LoadSession.url,
payload: { payload: {
savedSessionId: applicationUser.savedSessionId?.toString(), referralNumber: duplicate.referralNumber,
referralNumber: order.referralNumber?.toString(), referralDate: duplicate.responseDate,
referralDate: order.referralDate?.toString(),
parentAccountNumber: issConfig.parentAccountNumber, parentAccountNumber: issConfig.parentAccountNumber,
referralCorrelationId: order.referralCorrelationId referralCorrelationId: duplicate.referralCorrelationId
} }
}); });
const { data } = response; const { data } = response;
@ -1246,10 +1304,6 @@ export const useMainStore = defineStore({
return response; return response;
} }
applicationUser.crmCustomerId = data.applicationUser?.crmCustomerId;
applicationUser.experiments = data.applicationUser?.experiments ?? [];
applicationUser.savedSessionId = data.applicationUser?.savedSessionId;
if (order.policy.policyLookupSuccessful) { if (order.policy.policyLookupSuccessful) {
order.customer.emailAddress = data.customer?.emailAddress; order.customer.emailAddress = data.customer?.emailAddress;
order.customer.firstName = data.customer?.firstName; order.customer.firstName = data.customer?.firstName;
@ -1791,6 +1845,66 @@ export const useMainStore = defineStore({
// context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData); // context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData);
return addPricesToLineItems(availableLineItems, response.data.lineItems); return addPricesToLineItems(availableLineItems, response.data.lineItems);
}, },
// Tax order actions
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;
const serviceLocationState = serviceLocation.state;
const serviceLocationZipCode = serviceLocation.zipCode;
const flattenedLineItemsWithChildParts = getFlattenedArrayOfLineItemsWithChildParts(pricedLineItems);
const lineItemsWithOnlyPriceInfo = flattenedLineItemsWithChildParts.map((lineItem) => ({
partNumber: lineItem.partNumber,
laborAmount: lineItem.laborAmount ?? 0,
kitPrice: lineItem.kitPrice ?? 0,
sellingPrice: lineItem.sellingPrice ?? 0
}));
const pricedLineItemsFormattedForRequest = buildQueryStringParameterFromArrayOfComplexObjects(
lineItemsWithOnlyPriceInfo,
'lineItems'
);
let queryString = '';
if (appointmentType === 'Mobile') {
queryString =
`ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}`
+ `&BillToAccountNumber=${billToAccountNumber}`
+ `&ProviderNumber=${providerNumber}`
+ `&AppointmentType=${appointmentType}`
+ `&ServiceLocation.City=${serviceLocationCity}`
+ `&ServiceLocation.State=${serviceLocationState}`
+ `&ServiceLocation.ZipCode=${serviceLocationZipCode}`
+ `&${pricedLineItemsFormattedForRequest}`;
} else {
queryString =
`ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}`
+ `&BillToAccountNumber=${billToAccountNumber}`
+ `&ProviderNumber=${providerNumber}`
+ `&AppointmentType=${appointmentType}`
+ `&${pricedLineItemsFormattedForRequest}`;
}
const lineItemServerData = this.order.lineItems.serverData;
if (lineItemServerData) {
queryString += `&ServerData=${encodeURIComponent(lineItemServerData)}`;
}
const retPricedLineItems = await globalMethods.callHttpClient({
method: endpoints.TaxOrderItems.method,
endpoint: `${endpoints.TaxOrderItems.url}?${queryString}`
}).then((response) => {
this.order.lineItems.serverData = response.data.serverData;
return addTaxesToPricedLineItems(pricedLineItems, response.data.taxedLineItems);
});
return retPricedLineItems;
},
saveProviderPreferenceData(data) { saveProviderPreferenceData(data) {
this.updatePageData({ page: issPageValues.PROVIDER_PREFERENCE, data }); this.updatePageData({ page: issPageValues.PROVIDER_PREFERENCE, data });
}, },
@ -2156,6 +2270,7 @@ export const useMainStore = defineStore({
this.resetDamageState(); this.resetDamageState();
this.resetInsurance(); this.resetInsurance();
this.resetBailout(); this.resetBailout();
this.resetSubmittedOrder();
}, },
savePaymentMethodChoice(paymentMethod) { savePaymentMethodChoice(paymentMethod) {
const isPayInAdvance = paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE; const isPayInAdvance = paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE;
@ -2180,6 +2295,7 @@ export const useMainStore = defineStore({
} }
const submittedOrder = this.order; const submittedOrder = this.order;
const { experiments } = this.applicationUser; const { experiments } = this.applicationUser;
const { issConfig } = this;
// set to local storage // set to local storage
window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder));
@ -2187,6 +2303,8 @@ export const useMainStore = defineStore({
// clear vuex // clear vuex
this.resetState(); this.resetState();
// restore issConfig
this.issConfig = issConfig;
// restore user's experiments // restore user's experiments
this.applicationUser.experiments = experiments; this.applicationUser.experiments = experiments;
}, },
@ -2295,6 +2413,21 @@ function addPricesToLineItems(lineItems, pricingLineItems) {
return lineItems; return lineItems;
} }
function addTaxesToPricedLineItems(pricedLineItems, taxingLineItems = []) {
pricedLineItems.forEach((pricedLineItem) => {
const lineItemIndex = taxingLineItems.findIndex((taxingLineItem) => taxingLineItem.partNumber === pricedLineItem.partNumber);
if (pricedLineItem.childParts) {
addTaxesToPricedLineItems(pricedLineItem.childParts, taxingLineItems);
}
const taxedLineItem = taxingLineItems.splice(lineItemIndex, 1)[0];
pricedLineItem.salesTax = taxedLineItem?.salesTax ?? 0;
});
return pricedLineItems;
}
function getLineItemQueryStringForPricing(lineItems) { function getLineItemQueryStringForPricing(lineItems) {
return lineItems.map((lineItem, index) => { return lineItems.map((lineItem, index) => {
let queryStringSnippet = `&LineItems[${index}].partNumber=${lineItem.partNumber}`; let queryStringSnippet = `&LineItems[${index}].partNumber=${lineItem.partNumber}`;

View file

@ -961,10 +961,7 @@ describe('Store', () => {
describe('loadSession method', () => { describe('loadSession method', () => {
describe('successful method call', () => { describe('successful method call', () => {
const applicationUser = { const applicationUser = {
crmCustomerId: getRandomString(6, 6), experiments: getRandomString(6, 6)
experiments: getRandomString(6, 6),
pageData: getRandomString(6, 6),
savedSessionId: getRandomString(6, 6)
}; };
const vehicle = { const vehicle = {
year: getRandomString(6, 6), year: getRandomString(6, 6),
@ -1006,9 +1003,13 @@ describe('Store', () => {
it('calls load session api endpoint', async () => { it('calls load session api endpoint', async () => {
// Arrange // Arrange
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({ data: {} })); globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({ data: {} }));
const duplicate = {
referralNumber: getRandomString(6, 6),
referralCorrelationId: getRandomGuid()
};
// Act // Act
store.loadSession(); store.loadSession(duplicate);
// Asserts // Asserts
expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining({ expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining({
@ -1020,34 +1021,31 @@ describe('Store', () => {
// Arrange // Arrange
const response = { data: { ReferralNumber: getRandomString(6, 6) } }; const response = { data: { ReferralNumber: getRandomString(6, 6) } };
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response)); globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
const duplicate = {
referralNumber: getRandomString(6, 6),
referralCorrelationId: getRandomGuid()
};
// Act // Act
const result = store.loadSession(); const result = store.loadSession(duplicate);
// Asserts // Asserts
await expect(result).resolves.toBe(response.data); await expect(result).resolves.toBe(response.data);
}); });
it('sets expected application user data', async () => {
// Arrange
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse));
// Act
await store.loadSession();
// Asserts
expect(store.applicationUser.experiments).toEqual(applicationUser.experiments);
expect(store.applicationUser.savedSessionId).toBe(applicationUser.savedSessionId);
expect(store.applicationUser.crmCustomerId).toBe(applicationUser.crmCustomerId);
});
it('sets expected vehicle data', async () => { it('sets expected vehicle data', async () => {
// Arrange // Arrange
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse)); globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse));
const duplicate = {
referralNumber: getRandomString(6, 6),
referralCorrelationId: getRandomGuid()
};
store.order.policy.policyLookupSuccessful = true; store.order.policy.policyLookupSuccessful = true;
store.policy.vehicles = [{ vin: vehicle.vin }]; store.policy.vehicles = [{ vin: vehicle.vin }];
// Act // Act
await store.loadSession(); await store.loadSession(duplicate);
// Asserts // Asserts
expect(store.vehicle.year).toBe(vehicle.year); expect(store.vehicle.year).toBe(vehicle.year);
@ -1061,11 +1059,16 @@ describe('Store', () => {
// Arrange // Arrange
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse)); globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse));
const duplicate = {
referralNumber: getRandomString(6, 6),
referralCorrelationId: getRandomGuid()
};
store.order.policy.policyLookupSuccessful = true; store.order.policy.policyLookupSuccessful = true;
store.policy.vehicles = [{ vin: vehicle.vin }]; store.policy.vehicles = [{ vin: vehicle.vin }];
// Act // Act
await store.loadSession(); await store.loadSession(duplicate);
// Asserts // Asserts
expect(store.order.customer.address.streetAddress).toBe(customer.address.streetAddress); expect(store.order.customer.address.streetAddress).toBe(customer.address.streetAddress);
@ -1081,10 +1084,14 @@ describe('Store', () => {
it('sets expected remaining order data', async () => { it('sets expected remaining order data', async () => {
// Arrange // Arrange
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse)); globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse));
const originalWorkOrderNumber = store.order.workOrderNumber;
const duplicate = {
referralNumber: getRandomString(6, 6),
referralCorrelationId: getRandomGuid()
};
// Act // Act
await store.loadSession(); await store.loadSession(duplicate);
// Asserts // Asserts
expect(store.order.referralNumber).toBe(fullApiResponse.data.referralNumber); expect(store.order.referralNumber).toBe(fullApiResponse.data.referralNumber);
@ -1092,7 +1099,6 @@ describe('Store', () => {
expect(store.order.referralCorrelationId).toBe(fullApiResponse.data.referralCorrelationId); expect(store.order.referralCorrelationId).toBe(fullApiResponse.data.referralCorrelationId);
expect(store.order.referralSequenceNumber).toBe(fullApiResponse.data.referralSequenceNumber); expect(store.order.referralSequenceNumber).toBe(fullApiResponse.data.referralSequenceNumber);
expect(store.order.eon).toBe(fullApiResponse.data.eon); expect(store.order.eon).toBe(fullApiResponse.data.eon);
expect(store.order.workOrderNumber).toBe(originalWorkOrderNumber);
}); });
}); });
it('api call throws exception', async () => { it('api call throws exception', async () => {
@ -1100,8 +1106,13 @@ describe('Store', () => {
const error = 'load session error'; const error = 'load session error';
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject(error)); globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject(error));
const duplicate = {
referralNumber: getRandomString(6, 6),
referralCorrelationId: getRandomGuid()
};
// Act // Act
await store.loadSession().catch((e) => { await store.loadSession(duplicate).catch((e) => {
expect(e).toEqual(error); expect(e).toEqual(error);
}); });