SSR-1183 ITAC Pricing Endpoint

This commit is contained in:
Josh Dassinger 2024-06-13 14:36:17 -05:00
parent bb152140ea
commit 46f6a93745
10 changed files with 134 additions and 86 deletions

View file

@ -76,6 +76,10 @@ const endpoints = Object.freeze({
url: `${PRICE_BASE_URL}/order-items-with-insurance-pricing`,
method: 'GET'
},
GetITACPriceOrderItems: {
url: `${PRICE_BASE_URL}/order-items-with-itac-pricing`,
method: 'POST'
},
GetProviders: {
url: `${LOCATION_BASE_URL}/providers`,
method: 'GET'

View file

@ -28,7 +28,7 @@ export async function getPricedMobileFeePart(serviceZipCode) {
// Get the Mobile Fee Part Price
const pricingResults = await useMainStore()
.getPriceOrderItems([mobileFeePart.data]);
.getInsurancePriceOrderItems([mobileFeePart.data]);
return Promise.resolve(pricingResults[0]);
}

View file

@ -668,32 +668,7 @@ describe('coverageStatement.vue', () => {
});
});
});
describe('ITAC CoverageType', () => {
test('set ITAC coverageType once component is initialized', async () => {
// Arrange
const mainInitialState = {
order: {
insuranceCoverage: {
coverageStatus: coverageStatuses.VERIFIED,
coverageType: coverageType.Deductible
},
currentDeductible: 666
}
};
getPriceOfLineItems.mockReturnValue(333);
const { wrapper } = getMountedComponent(mainInitialState);
// Act
await wrapper.vm.initializeComponent();
// Assert
expect(wrapper.vm.mainStore.updateCoverageType)
.toHaveBeenCalledTimes(1);
expect(wrapper.vm.mainStore.updateCoverageType)
.toHaveBeenCalledWith(coverageType.ITAC);
});
describe('claim registration api call', () => {
it('Loaded duplicate with previously registered claim => claim registration is not called', async () => {
// Arrange
const sellingPrice = getRandomInt(50, 100);
@ -722,7 +697,14 @@ describe('coverageStatement.vue', () => {
useMainStore().getWipers = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getRainDefense = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve([
useMainStore().getInsurancePriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve([
{
sellingPrice,
kitPrice: 0,
laborAmount: 0
}
]));
useMainStore().getITACPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve([
{
sellingPrice,
kitPrice: 0,
@ -743,15 +725,14 @@ describe('coverageStatement.vue', () => {
// Assert
expect(wrapper.vm.mainStore.registerClaim).toHaveBeenCalledTimes(0);
});
});
describe('claim registration api call', () => {
it('claim registration not required => method not called', async () => {
// Arrange
const mockStoreActions = () => {
useMainStore().getWipers = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getRainDefense = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getInsurancePriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getITACPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
};
const { wrapper } = getMountedComponent({
issConfig: {
@ -796,7 +777,8 @@ describe('coverageStatement.vue', () => {
useMainStore().getWipers = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getRainDefense = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getInsurancePriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
useMainStore().getITACPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
};
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
const next = (method) => { method(wrapper.vm); };

View file

@ -124,7 +124,6 @@ import widgetFields from '@/constants/cms-widget-fields.js';
import { formatAmountInDollars } from '@/helpers/text-helper.js';
import showIssLoadingModal from '@/helpers/loading-modal-helper';
import { getPriceOfLineItems } from '@/helpers/price-calculator';
import coverageType from '@/constants/coverage-type';
import coverageStatuses from '@/constants/coverage-statuses';
const SAFELITE_PROVIDER = 'Safelite';
@ -146,8 +145,7 @@ export default {
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to?.query?.issPage);
const supportingItemsPromise =
await useMainStore().getSupportingItems();
const supportingItemsPromise = await useMainStore().getSupportingItems();
// Settle promises and get results
const promiseResultMap = [
@ -162,53 +160,23 @@ export default {
];
const resultMap = await settleAllPromises(promiseResultMap);
const clonedGlassParts = useMainStore().lineItems.glassParts
? JSON.parse(JSON.stringify(useMainStore().lineItems.glassParts))
: [];
// TODO SSR-1165: Recycle fee needs removed from quote calculation
const availableLineItems = [
...(resultMap.supportingItems ?? []),
...(clonedGlassParts ?? [])
];
let hasBailedOut = false;
let pricingResults = [];
const { vehicle, isPolicyLookupSuccessful, isITAC, isDeductible } = useMainStore();
if (isPolicyLookupSuccessful && vehicle.policyVehicleId >= 0) {
if (isITAC || isDeductible) {
await useMainStore().getFinalDeductible();
}
pricingResults = await useMainStore()
.getPriceOrderItems(availableLineItems)
.catch((err) => {
useMainStore().setBailout(bailoutMessage.pricingResponseError(
availableLineItems.map((li) => li.partNumber),
{
code: err.code,
message: err.message,
data: err.data
}
));
hasBailedOut = true;
next(`/?issPage=${issPageValues.BAILOUT_PAGE}`);
});
}
if (!hasBailedOut) {
// Call the "next" function to complete the transition to this page.
next(async (vm) => {
showIssLoadingModal(true);
vm.setCmsContent(resultMap.cmsContent);
vm.setSupportingItems(resultMap.supportingItems);
// eslint-disable-next-line no-param-reassign
vm.setBaseServiceLineItems(pricingResults);
await vm.initializeComponent();
if (!vm.unverified) {
useMainStore().disableKeyFields();
}
});
}
next(async (vm) => {
showIssLoadingModal(true);
vm.setCmsContent(resultMap.cmsContent);
vm.setSupportingItems(resultMap.supportingItems);
await vm.initializeComponent();
if (!vm.unverified) {
useMainStore().disableKeyFields();
}
});
},
setup() {
const mainStore = useMainStore();
@ -372,12 +340,30 @@ export default {
this.mainStore.updateCoverageStatus(coverageStatuses.VERIFIED);
}
// TODO this should be determined based on the result of the ITAC price call
// TODO it seems that ITAC now requires claim registration calls. If this call fails
if (this.mainStore.isVerified
&& this.mainStore.isDeductible
&& this.deductibleValue > this.totalServicePrice) {
this.mainStore.updateCoverageType(coverageType.ITAC);
if (this.mainStore.isVerified) {
const clonedGlassParts = useMainStore().lineItems.glassParts
? JSON.parse(JSON.stringify(useMainStore().lineItems.glassParts))
: [];
const availableLineItems = [
...(this.supportingItems ?? []),
...(clonedGlassParts ?? [])
];
const pricingResults = await useMainStore()
.getITACPriceOrderItems(availableLineItems)
.catch((err) => {
useMainStore().setBailout(bailoutMessage.pricingResponseError(
availableLineItems.map((li) => li.partNumber),
{
code: err.code,
message: err.message,
data: err.data
}
));
this.navigateWithScenario(navigationScenarios.PRICING_LOOKUP_ERROR);
});
this.setBaseServiceLineItems(pricingResults);
}
showIssLoadingModal(false);

View file

@ -141,7 +141,7 @@ export default {
let hasBailedOut = false;
const pricedVaps = await useMainStore()
.getPriceOrderItems(unpricedVaps)
.getInsurancePriceOrderItems(unpricedVaps)
.catch((err) => {
useMainStore().setBailout(bailoutMessage.pricingResponseError(
unpricedVaps.map((li) => li.partNumber),

View file

@ -261,7 +261,7 @@ export default {
const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
if (result.data) {
return useMainStore().getPriceOrderItems(result.data);
return useMainStore().getInsurancePriceOrderItems(result.data);
}
return result.data;
});

View file

@ -129,7 +129,7 @@ export default {
let hasBailedOut = false;
const pricingResults = await store
.getPriceOrderItems(availableLineItems)
.getInsurancePriceOrderItems(availableLineItems)
.catch((err) => {
useMainStore().setBailout(bailoutMessage.pricingResponseError(
availableLineItems.map((li) => li.partNumber),

View file

@ -67,6 +67,7 @@ const navigationScenarios = Object.freeze({
// Coverage Statement
CLICKED_BACK_WITH_REPAIR: 'CLICKED_BACK_WITH_REPAIR',
CLICKED_FORWARD_WITH_INVALID_STATE: 'CLICKED_FORWARD_WITH_INVALID_STATE',
PRICING_LOOKUP_ERROR: 'PRICING_LOOKUP_ERROR',
// TPA Search
CLICKED_DO_NOT_SEE_MY_SHOP_LINK: 'CLICKED_DO_NOT_SEE_MY_SHOP_LINK',

View file

@ -535,6 +535,10 @@ const routingTable = () => [
{
scenario: navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE,
destinationIssPageValue: issPageValues.BAILOUT_PAGE
},
{
scenario: navigationScenarios.PRICING_LOOKUP_ERROR,
destinationIssPageValue: issPageValues.BAILOUT_PAGE
}
]
},

View file

@ -1036,7 +1036,7 @@ export const useMainStore = defineStore({
});
},
async getPriceOrderItems(availableLineItems) {
async getInsurancePriceOrderItems(availableLineItems) {
const zipCodeToUse = this.order.serviceLocation.zipCode;
if (!this.order.serviceLocation.zipCodeCtu) {
const zipInfo = await this.validateZip({ zip: zipCodeToUse });
@ -1081,6 +1081,77 @@ export const useMainStore = defineStore({
return availableLineItems;
},
async getITACPriceOrderItems(availableLineItems) {
const zipCodeToUse = this.order.serviceLocation.zipCode;
if (!this.order.serviceLocation.zipCodeCtu) {
const zipInfo = await this.validateZip({ zip: zipCodeToUse });
this.order.serviceLocation.zipCodeCtu = zipInfo.zipCodeCtu;
}
const { policy, vehicle, contactInfo, serviceLocation, insuranceCoverage } = this.order;
const response = await globalMethods
.callHttpClient({
method: endpoints.GetITACPriceOrderItems.method,
endpoint: endpoints.GetITACPriceOrderItems.url,
payload: {
Eon: this.order.eon,
ReferralNumber: this.order.referralNumber,
ReferralSequenceNumber: this.order.referralSequenceNumber,
ReferralDate: `${this.order.referralDate}Z`,
lineItems: availableLineItems,
ServerData: this.order.lineItems.serverData,
ServiceZipCode: zipCodeToUse,
Customer: {
PhoneNumber: contactInfo.servicePhone,
State: policy.damageState,
ZipCode: policy.policyZipCode
},
Provider: {
ProviderNumber: serviceLocation.zipCodeCtu,
ProviderCtuNumber: serviceLocation.zipCodeCtu
},
Vehicle: {
CarId: vehicle.carId,
Year: vehicle.year,
Make: vehicle.make,
Model: vehicle.model
},
Insurance: {
AccountNumber: this.order.parentAccountNumber,
Deductible: this.order.currentDeductible ?? 7777,
LineOfBusiness: 'PERSONAL',
PolicyNumber: policy.policyNumber,
CoverageStatus: insuranceCoverage.coverageStatus,
IsNoComp: this.isNoComp
}
}
}).catch((error) => {
console.error(error);
throw error;
});
const { lineItems, serverData, isItac } = response.data;
if (serverData) {
this.order.lineItems.serverData = serverData;
}
if (isItac) {
this.updateCoverageType(coverageType.ITAC);
await this.getBillToInfo();
} else if (this.isITAC) {
this.updateCoverageType(coverageType.Deductible);
await this.getBillToInfo();
}
if (lineItems) {
const retAvailableLineItems = addPricesToLineItems(availableLineItems, lineItems);
return retAvailableLineItems;
}
return availableLineItems;
},
getMobileFeePart() {
const damageType = this.damage.isRepair ? 'Repair' : 'Replace';
@ -1670,7 +1741,7 @@ export const useMainStore = defineStore({
)
];
await this.getPriceOrderItems(lineItemsToTax);
await this.getInsurancePriceOrderItems(lineItemsToTax);
await this.getTaxOrderItems(lineItemsToTax);
},
@ -2295,7 +2366,7 @@ export const useMainStore = defineStore({
providerNumber: order.serviceLocation.zipCodeCtu.toString(),
typeOfClaim: 'GLASS ONLY',
lineOfBusiness: 'PERSONAL',
isItac: false
isItac: this.isITAC
});
const response = await globalMethods.callHttpClient({