Merge branch 'develop' into feature/CASH-48-frontend

This commit is contained in:
AdamCaouetteSafelite 2025-01-28 10:07:31 -05:00 committed by GitHub
commit 7b6a8eeeae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 469 additions and 84 deletions

View file

@ -27,7 +27,6 @@ module.exports = {
"!src/layouts/insurance/*.vue", // Temp test exclusion while in development
"!src/layouts/insurance-company/*.vue", // Temp test exclusion while in development
"!src/layouts/insurance-company/insurance-company-question/*.vue", // Temp test exclusion while in development
"!src/layouts/return-user/*.vue", // Temp test exclusion while in development
// END
], // ! means exclude from coverage.
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],

View file

@ -16,6 +16,8 @@ const storeMutations = {
UPDATE_VEHICLE_IMAGE_COLOR: "updateVehicleImageColor",
UPDATE_VEHICLE_VIN: "updateVehicleVin",
UPDATE_VEHICLE: "updateVehicle",
UPDATE_VEHICLE_MOBILE_STATIC_RECALIBRATION_APPLICABLE:
"updateIsMobileStaticRecalibrationApplicable",
UPDATE_IS_REPAIR: "updateIsRepair",
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",

View file

@ -97,16 +97,16 @@ export default {
document.onkeydown = function (e) {
return false;
};
// check session expired and initSession to recreate cookies
if (analyticsMixin.methods.sessionExpired()) {
// check session expired and initSession to recreate cookies
if (analyticsMixin.methods.sessionExpired()) {
this.routeReturnUser();
} else {
this.$emit("ForwardClicked");
}
},
linkClick() {
// check session expired and initSession to recreate cookies
if (analyticsMixin.methods.sessionExpired()) {
// check session expired and initSession to recreate cookies
if (analyticsMixin.methods.sessionExpired()) {
this.routeReturnUser();
} else {
this.$emit("BackClicked");

View file

@ -8,3 +8,17 @@ export function getQuerystringParameter(key) {
return lowerCaseParams.get(key) ? lowerCaseParams.get(key) : null;
}
// if you add the fmgPage to the querystringobject before calling, then pass true for skipFmgPageName
export function buildQuerystringObject(qso, skipFmgPageName=false) {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
for (const [name, value] of urlParams) {
if (name.toLowerCase() === "fmgpage" && skipFmgPageName) {
continue;
}
qso[name] = value;
}
return qso;
}

View file

@ -298,7 +298,7 @@ export default {
// to restore, uncomment the 2 lines below
// vm.showSaveProgressPopup = showSaveProgressPopup;
// vm.showSaveProgressModal = showSaveProgressModal;
vm.addableVaps = addableVaps;
vm.lineItems = lineItems;
vm.availableLineItems = pricingResults;

View file

@ -0,0 +1,312 @@
// Components
import returnUser from "@/layouts/return-user/return-user.vue";
// Supporting Files
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper";
import baseMixin from "@/mixins/base-mixin.js";
import { dispatchStoreAction } from "@/mixins/base-mixin.js";
import store from "@/store";
import router from "@/router";
import navbar from "@/fmg-components/nav-bar/nav-bar";
import { Form } from "vee-validate";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
import { settleAllPromises } from "@/helpers/layout-helper";
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
import { experimentSettings } from "../../constants/experiments";
import { storeActions } from "@/constants/store-actions";
import buttonMain from "@/ux-components/button-main/button-main";
// Constants
// Setup global mocks
let mockStoreActionData = {};
let mockStoreData = {};
let mockExperimentSettings = {
experiments: [
{
universeName: "ConceptFunnel",
settings: {
SuppressVinCapture: false,
},
},
],
};
function resetMockStoreData() {
mockStoreData = {
vehicle: {
year: "2000",
make: "TestMake",
model: "TestModel",
style: "TestStyle",
carId: "TestID",
vin: null,
registration: {
licensePlate: null,
},
},
serviceLocation: {
address: null,
address2: null,
city: null,
state: null,
zipCode: null,
zipCodeCtu: null,
appointmentType: null,
isVehicleProtected: null,
provider: {
providerNumber: null,
address: {
streetAddress: null,
city: null,
state: null,
zipCode: null,
zipCodeCtu: null,
},
},
techNotes: null,
},
customer: {
firstName: null,
lastName: null,
emailAddress: null,
phoneNumber: null,
isSmsOptIn: null,
},
damage: {
isRepair: false,
numberOfChips: null,
glassToReplace: [{ glassLocation: "Windshield", glassName: "windshield" }],
partQuestionAnswers: null,
moldingQuestionAnswers: null,
capabilityQuestionAnswers: null,
dateOfLoss: null,
damageCause: null,
},
lineItems: {
glassParts: [
{
canSafeliteRecalibrate: true,
childParts: [
{
kitPrice: 0,
laborAmount: 23.55,
partNumber: "GGG FW4896",
salesTax: 1.77,
sellingPrice: 0,
},
],
color: "Green Tint",
description:
"solar, soundproofing, lane keep assist, lane departure warning system, w/adaptive cruise control",
id: "db22fd44-10dd-456f-979b-ff88cf68cca6",
kitPrice: 0,
laborAmount: 60,
partNumber: "FW04896GTYN",
partType: "WINDSHIELD",
recalibrationType: "STATIC",
requiresCapabilityQuestions: false,
requiresRecalibration: true,
salesTax: 63.86,
sellingPrice: 791.46,
},
],
supportingItems: null,
vaps: null,
serverData: null,
promos: null,
},
payment: {
isInsurance: null,
insuranceCoverage: {
isVerified: null,
coverageStatus: null,
coverageType: null,
coverageVerificationType: null,
},
parentAccountNumber: 0,
billToAccountNumber: null,
isPia: null,
piaType: null,
inactivePromos: null,
paypalToken: null,
nextGenSettledAmount: 0,
ccToken: {
subscriptionId: null,
expMonth: null,
expYear: null,
cardType: null,
billToPostalCode: null,
billToFirstName: null,
billToLastName: null,
referenceNumber: null,
authCode: null,
transactionId: null,
transReferenceNumber: null,
lastFour: null,
},
},
policy: {
currentDeductible: 0,
policyNumber: null,
isItac: false,
additionalAuthFlag: null,
isNoComp: false,
insuranceCompanyName: null,
},
schedule: {
date: null,
startTime: null,
endTime: null,
routeCode: null,
jobMaxMinutes: null,
jobMinMinutes: null,
},
externalParameterServiceZip: {
zipCode: null,
emailAddress: null,
},
externalParameterState: { isExternalParameter: false },
};
}
function applyMockStoreDataToGetters() {
store.getters = {
vehicle: mockStoreData.vehicle,
};
store.state.order = mockStoreData;
store.state.applicationUser.experiments = mockExperimentSettings;
}
async function mockDispatchStoreAction(actionName) {
return mockStoreActionData[actionName];
}
jest.mock("@/mixins/base-mixin.js", () => ({
methods: {
dispatchStoreAction: jest.fn(),
dispatchStoreActionWithLogging: jest.fn().mockImplementation(mockDispatchStoreAction),
},
}));
jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: () => Promise.resolve("content"),
}));
jest.mock("@/helpers/heritage-integration/order-helper.js", () => ({
saveSession: jest.fn(),
}));
jest.mock("@/helpers/heritage-integration/cookie-helper", () => ({
deleteFunnelCookie: jest.fn(),
getFunnelCookie: jest.fn(),
}));
router.navigateWithoutSaving = jest.fn();
router.navigateWithSaving = jest.fn();
// Tests
describe("return-user.vue", () => {
beforeEach(() => {
resetMockStoreData();
jest.clearAllMocks();
});
describe("Test prerequisites are valid and child components are rendered", () => {
test("expect pagePrerequisites are valid to be called", () => {
// Arrange
const wrapper = setupMocks({});
applyMockStoreDataToGetters();
// Act
const pagePrerequisitesSpy = jest.spyOn(wrapper.vm, "arePagePrerequisitesValid");
wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(pagePrerequisitesSpy).toBeCalled();
expect(getFunnelCookie).toHaveBeenCalled();
});
test("renders child components", () => {
const wrapper = setupMocks({});
expect(wrapper.findComponent(funnelHeader).exists()).toBe(true);
expect(wrapper.findComponent(funnelSubHeader).exists()).toBe(true);
expect(wrapper.findComponent(navbar).exists()).toBe(true);
});
});
describe("Navigation", () => {
test("Check forwardButtonAction is working", async () => {
// Arrange
const wrapper = setupMocks({});
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith(
navigationScenarios.CLICKED_FORWARD,
wrapper.vm.$route
);
});
test("expect functions in startOver to be called", async () => {
//Arrange
const wrapper = setupMocks({});
// Act
const dispatchStoreActionSpy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
await wrapper.vm.$nextTick();
await wrapper.vm.startOver();
// Assert
expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith(
navigationScenarios.CLICKED_FORWARD,
wrapper.vm.$route
);
expect(dispatchStoreActionSpy).toHaveBeenCalledWith(storeActions.RESET_STATE);
expect(deleteFunnelCookie).toHaveBeenCalled();
});
});
});
function setupMocks({ customMountOptions }) {
const route = { query: { fmgPage: "return-user" }, params: {} };
baseMixin.methods.ResetExternalParamsAndHideModal = jest.fn();
const mountOptions = getMountOptions({
...customMountOptions,
route: route,
});
mountOptions.global.mocks["$store"] = store;
mountOptions.global.mocks["$router"] = router;
baseMixin.methods.isFormValid = jest.fn().mockReturnValue(true);
mountOptions["attachTo"] = document.body;
const wrapper = shallowMount(returnUser, mountOptions, {
stubs: {
Form,
funnelHeader,
funnelSubHeader,
navbar,
loadingModal: true,
buttonMain,
},
});
return wrapper;
}

View file

@ -11,7 +11,10 @@ export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) {
// Get the Mobile Fee Part
const mobileFeePart = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_MOBILE_FEE_PART,
null,
{
serviceZipCode: serviceZipCode,
serviceZipCodeCtu: zipCodeData.zipCodeCtu,
},
pageNameToLog,
false
);

View file

@ -241,57 +241,46 @@ export default {
this.displayMismatchStateAndZipAlert = false;
},
async setMobileLocation() {
if (
this.internalModel.addressQuestions.zipCode !==
this.modelValue.addressQuestions.zipCode
) {
this.resetAlerts();
// Validate the Zip Code
const zipCodeData = await this.getZipCodeData(
this.internalModel.addressQuestions.zipCode,
this.resetAlerts();
// Validate the Zip Code
const zipCodeData = await this.getZipCodeData(
this.internalModel.addressQuestions.zipCode,
"service-location"
);
if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true;
this.resetModalButtonStyle();
} else if (zipCodeData.state != this.internalModel.addressQuestions.state) {
this.displayMismatchStateAndZipAlert = true;
this.resetModalButtonStyle();
} else {
// retrieve mobile fee part
const serviceZipCode = this.internalModel.addressQuestions.zipCode;
const mobileFeePart = await getPricedMobileFeePart(
serviceZipCode,
"service-location"
);
if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true;
this.resetModalButtonStyle();
} else if (zipCodeData.state != this.internalModel.addressQuestions.state) {
this.displayMismatchStateAndZipAlert = true;
this.resetModalButtonStyle();
} else {
// retrieve mobile fee part
const serviceZipCode = this.internalModel.addressQuestions.zipCode;
const mobileFeePart = await getPricedMobileFeePart(
serviceZipCode,
"service-location"
);
// retrieve serviceability details
const serviceabilityDetails = await getServiceabilityDetails(
serviceZipCode,
null,
"service-location"
);
// retrieve serviceability details
const serviceabilityDetails = await getServiceabilityDetails(
serviceZipCode,
null,
"service-location"
);
const billToAccountNumber = await getBillToAccountNumber(
this.internalModel.zipCodeCtu
);
const billToAccountNumber = await getBillToAccountNumber(
this.internalModel.zipCodeCtu
);
// update content related to service zip code
this.$emit("updated-mobile-fee-part", mobileFeePart);
this.$emit("updated-serviceability", serviceabilityDetails.data);
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
this.$emit("updated-mobile-ctu", zipCodeData.zipCodeCtu);
this.$emit("updated-bill-to-account-number", billToAccountNumber);
// update content related to service zip code
this.$emit("updated-mobile-fee-part", mobileFeePart);
this.$emit("updated-serviceability", serviceabilityDetails.data);
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
this.$emit("updated-mobile-ctu", zipCodeData.zipCodeCtu);
this.$emit("updated-bill-to-account-number", billToAccountNumber);
// update the page level model
this.$emit("update:modelValue", this.internalModel);
//Page advance to Schedule page
this.$emit("mobileLocationSelected");
}
} else {
// Update the page level model
// update the page level model
this.$emit("update:modelValue", this.internalModel);
//Page advance to Schedule page

View file

@ -181,6 +181,9 @@ beforeEach(() => {
zipCode: "43235",
state: "OH",
},
vehicle: {
isMobileStaticRecalibrationApplicable: true,
},
},
damage: {
isRepair: false,

View file

@ -159,6 +159,7 @@ import { defineRule } from "vee-validate";
import { errorMessages } from "@/constants/error-messages";
const MOBILE_FEE_PART_TYPE = "MOBILE FEE";
const MOBILE_STATIC_RECAL_FEE_PART_NUMBER = "RECAL MOBILE";
// DEFINE VALIDATION RULES
defineRule("mobile-location-required", (value) => {
@ -188,6 +189,8 @@ export default {
isRecalibrationServiceableInshop: null,
isGlassServiceableMobile: null,
isRecalibrationServiceableMobile: null,
isVehicleMobileStaticRecalibrationApplicable:
this.getIsVehicleMobileStaticRecalibrationApplicableFromStore(),
selectedAppointmentType: this.getSelectedAppointmentType(),
selectedProvider: this.getSelectedProvider(),
mobileFeePart: null,
@ -306,11 +309,21 @@ export default {
},
isServiceableMobile() {
if (this.isRecalibrationServiceableMobile !== null) {
return this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile;
return (
(this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile) ||
this.isMobileStaticRecalibrationApplicable
);
} else {
return this.isGlassServiceableMobile;
}
},
isMobileStaticRecalibrationApplicable() {
return (
this.isVehicleMobileStaticRecalibrationApplicable &&
this.mobileFeePart?.partNumber == MOBILE_STATIC_RECAL_FEE_PART_NUMBER &&
(this.isInsurance ? this.mobileFeePart?.isInsurable : true)
);
},
mobileFeeApplies() {
if (
this.mobileFeePart?.laborAmount > 0 ||
@ -349,7 +362,8 @@ export default {
return (
this.isServiceableInshop &&
this.isGlassServiceableMobile &&
this.isRecalibrationServiceableMobile === false
this.isRecalibrationServiceableMobile === false &&
!this.isMobileStaticRecalibrationApplicable
);
},
displayRecalibrationWarning() {
@ -485,6 +499,9 @@ export default {
getSelectedProvider() {
return store.getters.order.serviceLocation.provider;
},
getIsVehicleMobileStaticRecalibrationApplicableFromStore() {
return store.getters.order.vehicle.isMobileStaticRecalibrationApplicable;
},
resetMobileLocation() {
this.streetAddress = "";
this.apartmentNumberOrBusinessName = "";

View file

@ -97,7 +97,7 @@ export default {
// turned off Save Your Progress for 1/23/25 release
// to restore, uncomment line below
// vm.showSaveProgressModal = !(emailFromStore?.length > 0);
// Glass Part Question dynamic component
Object.keys(vm.$refs)
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)

View file

@ -117,6 +117,7 @@ export default {
modelOptions: [],
styleOptions: [],
displayNoServiceAlert: false,
isMobileStaticRecalibrationApplicable: this.getIsMobileStaticRecalibrationApplicable(),
};
},
@ -438,6 +439,8 @@ export default {
this.imageVifNumber = result?.data.imageVifNumber;
this.imageVifColor = result?.data.imageVifColor;
this.displayNoServiceAlert = !result?.data.canSafeliteService;
this.isMobileStaticRecalibrationApplicable =
result?.data.isMobileStaticRecalibrationApplicable;
},
resetAlert() {
this.displayNoServiceAlert = false;
@ -456,6 +459,8 @@ export default {
imageUrl: this.imageUrl,
imageVifNumber: this.imageVifNumber,
imageVifColor: this.imageVifColor,
isMobileStaticRecalibrationApplicable:
this.isMobileStaticRecalibrationApplicable,
},
false
);
@ -531,6 +536,9 @@ export default {
getImageVifColorfromStore() {
return store.getters.vehicle.imageVifColor;
},
getIsMobileStaticRecalibrationApplicable() {
return store.getters.vehicle.isMobileStaticRecalibrationApplicable;
},
},
components: {

View file

@ -712,16 +712,10 @@ export default {
return !areAllSessionCookiesSet();
},
// sessionExpired is true when one of the analytics cookies(sid, dxdev) has expired but we still have the funnelSessionInfo cookie
// sessionExpired is true when one of the analytics cookies(sid, dxdev) has expired but we still have the vehicle year in vuex
sessionExpired() {
const fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE) === "true";
const funnelCookieLastTouched = getFunnelCookie()?.LastTouched;
if (
this.noSession() &&
!fromHeritage &&
funnelCookieLastTouched !== null &&
funnelCookieLastTouched !== undefined
) {
if (this.noSession() && !fromHeritage && store.getters.order.vehicle?.year > 0) {
return true;
} else {
return false;

View file

@ -6,7 +6,7 @@ import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js"
import { routingTable } from "@/router/router-constants/routing-table.js";
import { globalEvents, globalEventTypes } from "@/constants/events";
import { queryStrings } from "@/constants/query-strings";
import { getQuerystringParameter } from "@/helpers/querystring-helper";
import { getQuerystringParameter, buildQuerystringObject } from "@/helpers/querystring-helper";
import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
import { fmgPageValues, funnelStartPageName } from "@/router/router-constants/fmgPage-values";
@ -57,7 +57,7 @@ const routes = [
log(` --from.redirectedFrom:>${JSON.stringify(from.redirectedFrom)}<`, "");
await analyticsMixin.methods.validateSession();
// after session is validated, remove the fromHeritage querystring if it exists so session expiration works
if (to.query) {
delete to.query[queryStrings.FROM_HERITAGE];
@ -100,27 +100,24 @@ const routes = [
}
// On entering the funnel "fresh", read cookie information, decide what to do next.
else if (from.redirectedFrom === undefined || fromReturnUser) {
// if entering the funnel from the content site, check and see if there is already a funnel cookie.
// if entering the funnel from the content site, check and see if there is already a vehicle year in vuex.
// if so, send them to return-user page.
const funnelCookieLastTouched = getFunnelCookie()?.LastTouched;
if (
fromContentSite &&
funnelCookieLastTouched !== null &&
funnelCookieLastTouched !== undefined &&
!toReturnUserPage
!toReturnUserPage &&
store.getters.order.vehicle?.year > 0
) {
log(" --from content site navigate to return user");
var qso = {
fmgPage: fmgPageValues.RETURN_USER,
};
const lg = getQuerystringParameter(queryStrings.LOG);
if (lg) {
qso[queryStrings.LOG] = true;
}
const newQueryString = buildQuerystringObject(qso, true);
log(" -- returnUser add querystring: " + JSON.stringify(newQueryString));
router.push({
path: "/",
query: Object.assign({}, qso),
query: Object.assign({}, newQueryString),
});
return;
}
@ -178,8 +175,7 @@ const routes = [
// clear part related state because heritage selected a new vehicle
if (
to.query.fmgPage === fmgPageValues.VEHICLE &&
eval(getFunnelCookie()?.HasDelayedClaimRegistration &&
!fromReturnUser)
eval(getFunnelCookie()?.HasDelayedClaimRegistration && !fromReturnUser)
) {
store.commit(storeMutations.RESET_GLASS_PARTS_STATE);
}
@ -187,7 +183,7 @@ const routes = [
// if coming from the return user page, clear the destination page so implicit navigation runs
log(" --to.query ", JSON.stringify(to.query));
if (fromReturnUser && to.query) {
log( " --clear to.query");
log(" --clear to.query");
delete to.query[queryStrings.FMG_PAGE];
//to.query[queryStrings.FMG_PAGE] = "";
@ -571,7 +567,7 @@ async function navigate(
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
const logQs = getQuerystringParameter(queryStrings.LOG);
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, logQs, false);
log("------------- router index.js navigate start -----------------");
log(" --scenario: ", scenario);
log(" --isSavingNavigation: ", isSavingNavigation);
@ -636,7 +632,7 @@ function getNavigationMap(scenario, currentRoute) {
function log(message, data) {
const log = getQuerystringParameter(queryStrings.LOG);
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, log, false);
data = data ?? "";
const outData = typeof data === "object" ? JSON.stringify(data) : data;

View file

@ -68,6 +68,7 @@ const getDefaultState = () => {
registration: {
licensePlate: null,
},
isMobileStaticRecalibrationApplicable: false,
},
serviceLocation: {
address: null,
@ -225,6 +226,10 @@ export const mutations = {
updateVehicleVin(state, vin) {
state.order.vehicle.vin = vin;
},
updateIsMobileStaticRecalibrationApplicable(state, isMobileStaticRecalibrationApplicable) {
state.order.vehicle.isMobileStaticRecalibrationApplicable =
isMobileStaticRecalibrationApplicable;
},
updateIsRepair(state, isRepair) {
state.order.damage.isRepair = isRepair;
},
@ -350,6 +355,8 @@ export const mutations = {
state.order.vehicle.imageUrl = vehicleInfo.imageUrl;
state.order.vehicle.imageVifNumber = vehicleInfo.imageVifNumber;
state.order.vehicle.imageColor = vehicleInfo.imageVifColor;
state.order.vehicle.isMobileStaticRecalibrationApplicable =
vehicleInfo.isMobileStaticRecalibrationApplicable;
},
updateRegistration(state, registrationInfo) {
state.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate;
@ -534,6 +541,7 @@ export const mutations = {
state.order.vehicle.imageUrl = null;
state.order.vehicle.imageVifNumber = null;
state.order.vehicle.imageColor = null;
state.order.vehicle.isMobileStaticRecalibrationApplicable = false;
},
resetDamageState(state) {
state.order.damage.isRepair = null;
@ -1634,7 +1642,7 @@ export const actions = {
return response;
},
getMobileFeePart(context, { pageNameToLog }) {
getMobileFeePart(context, { payload: { serviceZipCode, serviceZipCodeCtu }, pageNameToLog }) {
const serviceType = context.getters.damage.isRepair ? "Repair" : "Install";
const facilityType = "Mobile";
const parentAccountNumber = context.getters.payment.parentAccountNumber;
@ -1646,16 +1654,31 @@ export const actions = {
const coverageStatus = coverageStatusEnum(order.payment?.insuranceCoverage?.coverageStatus);
const coverageType = coverageTypeEnum(order.payment?.insuranceCoverage?.coverageType);
const isItacOptimized = order.policy?.isItac ?? false;
const isMobileStaticRecalibrationApplicable =
order.vehicle?.isMobileStaticRecalibrationApplicable;
const zipCode =
order.serviceLocation?.provider?.address?.zipCode ?? order.serviceLocation?.zipCode;
serviceZipCode ??
order.serviceLocation?.provider?.address?.zipCode ??
order.serviceLocation?.zipCode;
var providerNumber =
order.serviceLocation?.provider?.providerNumber ?? order.serviceLocation?.zipCodeCtu;
serviceZipCodeCtu ??
order.serviceLocation?.provider?.providerNumber ??
order.serviceLocation?.zipCodeCtu;
if (providerNumber.startsWith("00") && providerNumber.length > 5) {
providerNumber = providerNumber.substring(1);
}
var endPoint = `${endpoints.GetMobileFeePart.url}/?serviceType=${serviceType}&facilityType=${facilityType}&parentAccountNumber=${parentAccountNumber}&billToAccountNumber=${billToAccountNumber}&providerNumber=${providerNumber}&isItacOptimized=${isItacOptimized}&zipCode=${zipCode}`;
if (isMobileStaticRecalibrationApplicable) {
const staticRecalPartNumber = getStaticRecalPartNumber(order.lineItems?.glassParts[0]);
const carId = order.vehicle?.carId;
if (staticRecalPartNumber && carId) {
endPoint = `${endPoint}&partNumbers=${staticRecalPartNumber}&carId=${carId}`;
}
}
if (coverageStatus) {
endPoint = `${endPoint}&coverageStatus=${coverageStatus}`;
}
@ -2256,7 +2279,18 @@ export const actions = {
// Vehicle
saveVehicle(
context,
{ year, make, model, style, carId, category, imageUrl, imageVifNumber, imageVifColor }
{
year,
make,
model,
style,
carId,
category,
imageUrl,
imageVifNumber,
imageVifColor,
isMobileStaticRecalibrationApplicable,
}
) {
if (
context.state.order.vehicle.year != year ||
@ -2277,6 +2311,10 @@ export const actions = {
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, imageUrl);
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, imageVifNumber);
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, imageVifColor);
context.commit(
storeMutations.UPDATE_VEHICLE_MOBILE_STATIC_RECALIBRATION_APPLICABLE,
isMobileStaticRecalibrationApplicable
);
}
},
@ -3680,3 +3718,13 @@ function getExternalParameterDefaultState() {
function saveExternalParameterState(externalParameterState) {
window.sessionStorage.setItem("externalParameterState", JSON.stringify(externalParameterState));
}
//This function checks if static recalibration is available for the vehicle and returns the part number for it.
function getStaticRecalPartNumber(glassPartsArray) {
const recalPart = glassPartsArray.childParts.find((item) => item.partNumber === "RECAL STATIC");
if (recalPart) {
return recalPart.partNumber;
} else {
return null;
}
}