DigitalConsumer.FixMyGlass/src/store/index.js
scottkiener-at-safelite 87c1baf381 CASH-2916 | Consume new v2 endpoints for scheduling
Providers are now grouped for in-shop
They can accept ranges up to 180 but that is not needed yet
2026-07-07 12:08:59 -04:00

4692 lines
187 KiB
JavaScript

import { createStore } from "vuex";
import { endpoints } from "@/constants/endpoints.js";
import { storeMutations } from "@/constants/store-mutations";
import { sessionStorageKeyConstants } from "@/constants/session-storage.js";
import { getDateForSavedSessionTimeout } from "@/helpers/heritage-integration/session-helper";
import createPersistedState from "vuex-persistedstate";
import globalMethods from "@/global-methods";
import { storeActions } from "@/constants/store-actions";
import { applicationConfig } from "@/constants/application-config";
import { experimentTriggers } from "@/constants/experiments";
import { damageLocationsSelected } from "@/constants/damage-locations-selected";
import { routeData } from "@/router/constants/routes";
import {
deleteFunnelCookie,
getSessionIdValue,
getDeviceIdValue,
} from "@/helpers/heritage-integration/cookie-helper.js";
import { deepEqual } from "@/helpers/object-helper";
import baseMixin from "@/mixins/base-mixin.js";
import {
AppointmentTypeStrings,
PREMIUM_FEE_PART_TYPE,
RouteCodeFlags,
} from "@/constants/schedule-constants";
import { getQuerystringParameter } from "@/helpers/querystring-helper";
import { deepClone } from "@/helpers/object-helper";
import {
getExperimentSettingsFromExperimentList,
hasSettingEqualTo,
} from "../helpers/experiment-helper";
import { queryStrings } from "@/constants/query-strings";
import { partTypeStrings } from "@/constants/part-type-strings";
import {
convertDateStringToDate,
militaryToTwelveHourTime,
} from "@/layouts/schedule/helpers/schedule-helper";
import { getDisplayTextForDurationLength } from "@/helpers/duration-length-helper";
import { paymentMethods } from "@/constants/payment-method-constants";
import {
getPromoCodeWithoutBundleIdentifier,
removeCurrentlyActivePromoCodesFromInactivePromos,
} from "@/helpers/promotions-helper";
import { getDateDifferenceInDays, normalizeDotNetMinDate } from "@/helpers/date-helper";
import sharedMutations from "./vuex-shared-mutations/vuexSharedMutations";
import {
coverageStatus,
coverageStatusValue,
coverageStatusEnum,
coverageType,
coverageTypeValue,
coverageTypeEnum,
} from "@/constants/insurance";
import {
containsRecalParts,
getTopLevelPartsWithRecal,
isRecalPartOrHasChildRecalPart,
getRecalPartNumbers,
} from "@/helpers/recal-helper";
import { externalParameterStatus } from "@/constants/external-parameters";
import { experimentSettings } from "@/constants/experiments";
import { addPricesToLineItems, getAmountDue } from "@/helpers/pricing-helper";
// Export State
const getDefaultState = () => {
return {
order: {
vehicle: {
year: null,
make: null,
model: null,
style: null,
vehicleSubType: null,
vehicleSpecialClass: null,
isBigTruck: false,
carId: null,
category: null,
vin: null,
canSafeliteService: null,
imageUrl: null,
imageVifNumber: null,
imageColor: null,
registration: {
licensePlate: null,
},
skipVINLookup: false,
skipPartQuestions: false,
vinRequired: false,
},
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,
waitListRequested: null,
address: {
streetAddress: null,
streetAddress2: null,
city: null,
state: null,
zipCode: null,
},
},
damage: {
isRepair: null,
numberOfChips: null,
glassToReplace: null,
partQuestionAnswers: null,
moldingQuestionAnswers: null,
capabilityQuestionAnswers: null,
dateOfLoss: null,
damageCause: null,
installOemGlass: null,
},
lineItems: {
glassParts: null,
supportingItems: null,
vaps: null,
serverData: null,
promos: null,
},
payment: {
isInsurance: null,
insuranceCoverage: {
isVerified: null,
coverageStatus: null,
coverageSubStatus: null,
coverageType: null,
coverageVerificationType: null,
claimNumber: null,
},
parentAccountNumber: 0,
accountName: null,
isClaimAndCoverage: false,
canScheduleOnline: false,
isManagedAccount: false,
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,
originalDeductible: 0,
policyNumber: null,
isItac: false,
additionalAuthFlag: null,
isNoComp: false,
insuranceCompanyName: null,
phoneNumber: null,
phoneExtension: null,
dateOfBirth: null,
lossTime: null,
lossLocation: null,
lastName: null,
subrogation: null,
},
schedule: {
date: null,
startTime: null,
endTime: null,
routeCode: null,
jobMaxMinutes: null,
jobMinMinutes: null,
},
referralNumber: null,
referralSequenceNumber: null,
referralDate: null,
referralCorrelationId: null,
eon: null,
workOrderNumber: null,
workOrderId: null,
customerPortalLoginToken: null,
lockToken: null,
settledTenderAmount: 0,
isRecalAckOptIn: false,
isRecalAcknowledgedForScheduling: "",
isMSRFeeApplicable: false,
isMSRFeeCoveredByInsurance: false,
isNewInsuranceFlow: false,
},
applicationUser: {
eventBus: [],
pageData: {},
savedSessionTimeout: getDateForSavedSessionTimeout(),
saveSessionPromise: null,
savedSessionId: null,
crmCustomerId: null,
lastPageVisited: null,
experiments: [],
triggeredSiteEntry: false,
affiliateCookies: [],
loggingOption: false,
hasAlreadyTriggeredError: false,
},
idempotencyKeyFields: {
referralCorrelationId: null,
totalInCents: 0,
expiryTime: null,
idempotencyKey: null,
},
submittedStateRevision: 0,
};
};
export const state = getDefaultState();
export const externalParameterState = getExternalParameterDefaultState();
// Export Mutations
export const mutations = {
// VEHICLE MUTATIONS
updateYear(state, year) {
state.order.vehicle.year = year;
},
updateMake(state, make) {
state.order.vehicle.make = make;
},
updateModel(state, model) {
state.order.vehicle.model = model;
},
updateStyle(state, style) {
state.order.vehicle.style = style;
},
updateVehicleSubType(state, vehicleSubType) {
state.order.vehicle.vehicleSubType = vehicleSubType;
},
updateVehicleSpecialClass(state, vehicleSpecialClass) {
state.order.vehicle.vehicleSpecialClass = vehicleSpecialClass;
},
updateIsBigTruck(state, isBigTruck) {
state.order.vehicle.isBigTruck = isBigTruck;
},
updateCarId(state, carId) {
state.order.vehicle.carId = carId;
},
updateVehicleCategory(state, category) {
state.order.vehicle.category = category;
},
updateVehicleCanSafeliteService(state, canSafeliteService) {
state.order.vehicle.canSafeliteService = canSafeliteService;
},
updateSkipVINLookup(state, skipVINLookup) {
state.order.vehicle.skipVINLookup = skipVINLookup;
},
updateVinRequired(state, vinRequired) {
state.order.vehicle.vinRequired = vinRequired;
},
updateSkipPartQuestions(state, skipPartQuestions) {
state.order.vehicle.skipPartQuestions = skipPartQuestions;
},
updateSkipCapabilitiesQuestions(state, skipCapabilitiesQuestions) {
state.order.vehicle.skipCapabilitiesQuestions = skipCapabilitiesQuestions;
},
updateVehicleImageUrl(state, imageUrl) {
state.order.vehicle.imageUrl = imageUrl;
},
updateVehicleImageVifNumber(state, imageVifNumber) {
state.order.vehicle.imageVifNumber = imageVifNumber;
},
updateVehicleImageColor(state, imageColor) {
state.order.vehicle.imageColor = imageColor;
},
updateVehicleVin(state, vin) {
state.order.vehicle.vin = vin;
},
updateIsRepair(state, isRepair) {
state.order.damage.isRepair = isRepair;
},
updateNumberOfChips(state, numberOfChips) {
state.order.damage.numberOfChips = numberOfChips;
},
updateGlassToReplace(state, glassToReplace) {
state.order.damage.glassToReplace = glassToReplace;
},
updatePartQuestionAnswers(state, answersArray) {
state.order.damage.partQuestionAnswers = answersArray;
},
updateMoldingQuestionAnswers(state, answersArray) {
state.order.damage.moldingQuestionAnswers = answersArray;
},
updateCapabilityQuestionAnswers(state, answersArray) {
state.order.damage.capabilityQuestionAnswers = answersArray;
},
updateGlassParts(state, partsData) {
state.order.lineItems.glassParts = partsData;
},
updateVaps(state, partsData) {
state.order.lineItems.vaps = partsData;
},
updateSupportingItems(state, partsData) {
state.order.lineItems.supportingItems = partsData;
},
updateLineItemsServerData(state, serverData) {
state.order.lineItems.serverData = serverData;
},
updateInactivePromos(state, inactivePromos) {
state.order.payment.inactivePromos = inactivePromos;
},
updatePromos(state, promos) {
state.order.lineItems.promos = promos;
},
updatePageData(state, pageData) {
state.applicationUser.pageData[pageData.page] = pageData.data;
},
updateReferralCorrelationId(state, referralCorrelationId) {
state.order.referralCorrelationId = referralCorrelationId;
},
updateReferralNumber(state, referralNumber) {
state.order.referralNumber = referralNumber;
},
updateReferralSequenceNumber(state, referralSequenceNumber) {
state.order.referralSequenceNumber = referralSequenceNumber;
},
updateReferralDate(state, referralDate) {
state.order.referralDate = referralDate;
},
updateParentAcctNumber(state, parentAcctNumber) {
state.order.payment.parentAccountNumber = parentAcctNumber;
},
updateAccountName(state, accountName) {
state.order.payment.accountName = accountName;
state.order.policy.insuranceCompanyName = accountName;
},
updatePhoneNumber(state, phoneNumber) {
state.order.policy.phoneNumber = phoneNumber;
},
updatePhoneExtension(state, phoneExtension) {
state.order.policy.phoneExtension = phoneExtension;
},
updateStreetAddress(state, streetAddress) {
state.order.customer.address.streetAddress = streetAddress;
},
updateStreetAddress2(state, streetAddress2) {
state.order.customer.address.streetAddress2 = streetAddress2;
},
updateCity(state, city) {
state.order.customer.address.city = city;
},
updateState(state, stateValue) {
state.order.customer.address.state = stateValue;
},
updateZipCode(state, zipCode) {
state.order.customer.address.zipCode = zipCode;
},
updateClaimNumber(state, claimNumber) {
state.order.payment.insuranceCoverage.claimNumber = claimNumber;
},
updateIsClaimAndCoverage(state, isClaimAndCoverage) {
state.order.payment.isClaimAndCoverage = isClaimAndCoverage;
},
updateCanScheduleOnline(state, canScheduleOnline) {
state.order.payment.canScheduleOnline = canScheduleOnline;
},
updateIsManagedAccount(state, isManagedAccount) {
state.order.payment.isManagedAccount = isManagedAccount;
},
updateBillToAcctNumber(state, billToAcctNumber) {
state.order.payment.billToAccountNumber = billToAcctNumber;
},
updateEON(state, eon) {
state.order.eon = eon;
},
updateIsInsurance(state, isInsurance) {
state.order.payment.isInsurance = isInsurance;
},
resetInsuranceDetails(state) {
state.order.payment.insuranceCoverage = {
isVerified: null,
coverageStatus: null,
coverageSubStatus: null,
coverageType: null,
coverageVerificationType: null,
};
state.order.policy.policyNumber = null;
state.order.payment.insuranceCoverage.claimNumber = null;
state.order.policy.insuranceCompanyName = null;
state.order.customer.address.streetAddress = null;
state.order.customer.address.streetAddress2 = null;
state.order.customer.address.city = null;
state.order.customer.address.state = null;
state.order.customer.address.zipCode = null;
state.order.damage.dateOfLoss = null;
state.order.damage.damageCause = null;
},
updateIsPia(state, isPia) {
state.order.payment.isPia = isPia;
},
updatePiaType(state, piaType) {
state.order.payment.piaType = piaType;
},
updateWorkOrderNumber(state, workOrderNumber) {
state.order.workOrderNumber = workOrderNumber;
},
updateWorkOrderId(state, workOrderId) {
state.order.workOrderId = workOrderId;
},
updateCustomerPortalLoginToken(state, customerPortalLoginToken) {
state.order.customerPortalLoginToken = customerPortalLoginToken;
},
updateLockToken(state, lockToken) {
state.order.lockToken = lockToken;
},
updateSettledTenderAmount(state, settledTenderAmount) {
state.order.settledTenderAmount = settledTenderAmount;
},
updateIsRecalAckOptIn(state, isRecalAckOptIn) {
state.order.isRecalAckOptIn = isRecalAckOptIn;
},
updateIsRecalAcknowledgedForScheduling(state, isRecalAcknowledgedForScheduling) {
state.order.isRecalAcknowledgedForScheduling = isRecalAcknowledgedForScheduling;
},
updateIsOemGlassSelected(state, isOemGlassSelected) {
state.order.damage.installOemGlass = isOemGlassSelected;
},
updateIsMSRFeeApplicable(state, isMSRFeeApplicable) {
state.order.isMSRFeeApplicable = isMSRFeeApplicable;
},
updateIsMSRFeeCoveredByInsurance(state, isMSRFeeCoveredByInsurance) {
state.order.isMSRFeeCoveredByInsurance = isMSRFeeCoveredByInsurance;
},
updateIsNewInsuranceFlow(state, isNewInsuranceFlow) {
state.order.isNewInsuranceFlow = isNewInsuranceFlow;
},
updateCashPriceSubTotal(state, cashPriceSubTotal) {
state.order.cashPriceSubTotal =
cashPriceSubTotal === "" ? null : cashPriceSubTotal.toString();
},
updateCCToken(state, ccToken) {
state.order.payment.ccToken.subscriptionId = ccToken.subscriptionId;
state.order.payment.ccToken.expMonth = ccToken.expMonth;
state.order.payment.ccToken.expYear = ccToken.expYear;
state.order.payment.ccToken.cardType = ccToken.cardType;
state.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode;
state.order.payment.ccToken.billToFirstName = ccToken.billToFirstName;
state.order.payment.ccToken.billToLastName = ccToken.billToLastName;
state.order.payment.ccToken.referenceNumber = ccToken.referenceNumber;
state.order.payment.ccToken.authCode = ccToken.authCode;
state.order.payment.ccToken.transactionId = ccToken.transactionId;
state.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber;
state.order.payment.ccToken.lastFour = ccToken.lastFour;
},
updatePaypalToken(state, ppToken) {
state.order.payment.paypalToken = ppToken;
},
updateNextGenSettledAmount(state, nextGenSettledAmount) {
state.order.payment.nextGenSettledAmount = nextGenSettledAmount;
},
updateInsuranceVerifiedStatus(state, isVerified) {
state.order.payment.insuranceCoverage.isVerified = isVerified;
},
updateCustomerEmailAddress(state, customerEmailAddress) {
state.order.customer.emailAddress = customerEmailAddress;
},
updateCustomerPhoneNumber(state, phoneNumber) {
state.order.customer.phoneNumber = phoneNumber;
},
updateCustomerIsSmsOptin(state, isSmsOptIn) {
state.order.customer.isSmsOptIn = isSmsOptIn;
},
updateCustomerWaitListRequested(state, waitListRequested) {
state.order.customer.waitListRequested = waitListRequested;
},
updateVehicle(state, vehicleInfo) {
state.order.vehicle.year = vehicleInfo.year;
state.order.vehicle.make = vehicleInfo.make;
state.order.vehicle.model = vehicleInfo.model;
state.order.vehicle.style = vehicleInfo.style;
state.order.vehicle.carId = vehicleInfo.carId;
state.order.vehicle.category = vehicleInfo.category;
state.order.vehicle.vin = vehicleInfo.vin;
if (vehicleInfo.vinRequired !== undefined) {
state.order.vehicle.vinRequired = vehicleInfo.vinRequired;
}
state.order.vehicle.imageUrl = vehicleInfo.imageUrl;
state.order.vehicle.imageVifNumber = vehicleInfo.imageVifNumber;
state.order.vehicle.imageColor = vehicleInfo.imageVifColor;
},
updateRegistration(state, registrationInfo) {
state.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate;
},
updateServiceZip(state, serviceZipInfo) {
state.order.serviceLocation.state = serviceZipInfo.state || serviceZipInfo.payload?.state;
state.order.serviceLocation.zipCode =
serviceZipInfo.zipCode || serviceZipInfo.payload?.zipCode;
state.order.serviceLocation.zipCodeCtu =
serviceZipInfo.zipCodeCtu || serviceZipInfo.payload?.zipCodeCtu;
},
updateServiceLocation(state, serviceLocationInfo) {
state.order.serviceLocation.address = serviceLocationInfo.address;
state.order.serviceLocation.address2 = serviceLocationInfo.address2;
state.order.serviceLocation.city = serviceLocationInfo.city;
state.order.serviceLocation.state = serviceLocationInfo.state;
state.order.serviceLocation.zipCode = serviceLocationInfo.zipCode;
state.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu;
state.order.serviceLocation.appointmentType = serviceLocationInfo.appointmentType;
state.order.serviceLocation.isVehicleProtected = serviceLocationInfo.isVehicleProtected;
state.order.serviceLocation.provider = {
providerNumber: serviceLocationInfo.provider?.providerNumber,
address: {
streetAddress: serviceLocationInfo.provider?.address?.streetAddress,
city: serviceLocationInfo.provider?.address?.city,
state: serviceLocationInfo.provider?.address?.state,
zipCode: serviceLocationInfo.provider?.address?.zipCode,
zipCodeCtu: serviceLocationInfo.provider?.address?.zipCodeCtu,
},
};
},
updateMobileDetails(state, mobileDetails) {
state.order.serviceLocation.address = mobileDetails.address;
state.order.serviceLocation.address2 = mobileDetails.address2;
state.order.serviceLocation.city = mobileDetails.city;
state.order.serviceLocation.isVehicleProtected = mobileDetails.isVehicleProtected;
},
updateServiceLocationTechNotes(state, techNotes) {
state.order.serviceLocation.techNotes = techNotes;
},
updateSchedule(state, scheduleInfo) {
if (scheduleInfo) {
state.order.schedule.date = scheduleInfo.date;
state.order.schedule.startTime = scheduleInfo.startTime;
state.order.schedule.endTime = scheduleInfo.endTime;
state.order.schedule.routeCode = scheduleInfo.routeCode;
state.order.schedule.jobMaxMinutes = scheduleInfo.jobMaxMinutes;
state.order.schedule.jobMinMinutes = scheduleInfo.jobMinMinutes;
}
},
updateCustomerDetails(state, customerDetails) {
if (customerDetails) {
state.order.customer.firstName = customerDetails.firstName;
state.order.customer.lastName = customerDetails.lastName;
state.order.customer.emailAddress = customerDetails.emailAddress;
state.order.customer.phoneNumber = customerDetails.phoneNumber;
state.order.customer.isSmsOptIn = customerDetails.isSmsOptIn;
}
},
updateInsuranceDetails(state, insuranceDetails) {
if (insuranceDetails) {
state.order.policy.policyNumber = insuranceDetails.policyNumber;
state.order.customer.address.streetAddress = insuranceDetails.streetAddress;
state.order.customer.address.streetAddress2 = insuranceDetails.streetAddress2;
state.order.customer.address.city = insuranceDetails.city;
state.order.customer.address.state = insuranceDetails.state;
state.order.customer.address.zipCode = insuranceDetails.zipCode;
state.order.payment.insuranceCoverage.claimNumber = insuranceDetails.claimNumber;
state.order.policy.phoneNumber = insuranceDetails.phoneNumber;
state.order.policy.phoneExtension = insuranceDetails.phoneExtension;
state.order.policy.morePolicyQuestions = insuranceDetails.morePolicyQuestions;
state.order.policy.dateOfBirth = insuranceDetails.dateOfBirth;
state.order.policy.lossTime = insuranceDetails.lossTime;
state.order.policy.lastName = insuranceDetails.lastName;
state.order.policy.lossLocation = insuranceDetails.lossLocation;
state.order.policy.subrogation = insuranceDetails.subrogation;
state.order.policy.currentDeductible = insuranceDetails.currentDeductible;
state.order.policy.originalDeductible = insuranceDetails.originalDeductible;
state.order.payment.insuranceCoverage.coverageStatus = coverageStatusValue(
insuranceDetails.coverageStatus
);
state.order.payment.insuranceCoverage.coverageSubStatus =
insuranceDetails.coverageSubStatus;
}
},
updateDamageDetails(state, damageDetails) {
if (damageDetails) {
state.order.damage.dateOfLoss = damageDetails.dateOfLoss;
state.order.damage.damageCause = damageDetails.damageCause;
}
},
// applicationUser MUTATIONS
updateSaveSessionPromise(state, saveSessionPromise) {
state.applicationUser.saveSessionPromise = saveSessionPromise;
},
updateSavedSessionId(state, savedSessionId) {
state.applicationUser.savedSessionId = savedSessionId;
},
updateCrmCustomerId(state, crmCustomerId) {
state.applicationUser.crmCustomerId = crmCustomerId;
},
updateLastPageVisited(state, lastPageVisited) {
state.applicationUser.lastPageVisited = lastPageVisited;
},
updateLoggingOption(state, loggingOption) {
state.applicationUser.loggingOption = loggingOption;
},
// EVENT BUS MUTATIONS
addEventToBus(state, event) {
state.applicationUser.eventBus.push(event);
},
removeEventFromBus(state, eventData) {
const matchedEvent = state.applicationUser.eventBus.find(
({ category, subCategory }) =>
category === eventData.category && subCategory === eventData.subCategory
);
const itemIndex = state.applicationUser.eventBus.indexOf(matchedEvent);
// If the item exists, remove it.
if (itemIndex > -1) {
state.applicationUser.eventBus.splice(itemIndex, 1);
}
},
//ExternalParameter MUTATIONS
updateIsExternalParameter(state, isExternalParameter) {
externalParameterState.isExternalParameter = isExternalParameter;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterYear(state, year) {
externalParameterState.vehicle.year = year;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterMake(state, make) {
externalParameterState.vehicle.make = make;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterModel(state, model) {
externalParameterState.vehicle.model = model;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterStyle(state, style) {
externalParameterState.vehicle.style = style;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterQsStash(state, qsStash) {
externalParameterState.qsStash = qsStash;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterIsRepair(state, isRepair) {
externalParameterState.vehicleDamage.isRepair = isRepair;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterNumberOfChips(state, numberOfChips) {
externalParameterState.vehicleDamage.numberOfChips = numberOfChips;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterDamageType(state, damageType) {
externalParameterState.vehicleDamage.damageType = damageType;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterZipCode(state, zipCode) {
externalParameterState.serviceZip.zipCode = zipCode;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterEmailAddress(state, emailAddress) {
externalParameterState.customer.emailAddress = emailAddress;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterIsInsurance(state, isInsurance) {
externalParameterState.quote.isInsurance = isInsurance;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterVinSelection(state, vinSelection) {
externalParameterState.estimate.vinSelection = vinSelection;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterServicePackage(state, servicePackage) {
externalParameterState.quote.servicePackage = servicePackage;
saveExternalParameterState(externalParameterState);
},
updateExternalParameterPhoneNumber(state, phoneNumber) {
externalParameterState.customer.phoneNumber = phoneNumber;
saveExternalParameterState(externalParameterState);
},
//RESET ExternalParameter MUTATIONS
resetExternalParameterVehicleState(state) {
externalParameterState.vehicle.year = null;
externalParameterState.vehicle.make = null;
externalParameterState.vehicle.model = null;
externalParameterState.vehicle.style = null;
saveExternalParameterState(externalParameterState);
},
resetExternalParameterDamageState(state) {
externalParameterState.vehicleDamage.isRepair = null;
externalParameterState.vehicleDamage.numberOfChips = null;
externalParameterState.vehicleDamage.damageType = null;
saveExternalParameterState(externalParameterState);
},
resetExternalParameterEstimateState(state) {
externalParameterState.estimate.vinSelection = null;
saveExternalParameterState(externalParameterState);
},
resetExternalParameterServiceZipState(state) {
externalParameterState.serviceZip.zipCode = null;
saveExternalParameterState(externalParameterState);
},
resetExternalParameterQuoteState(state) {
externalParameterState.quote.servicePackage = null;
externalParameterState.quote.isInsurance = null;
saveExternalParameterState(externalParameterState);
},
resetIsExternalParameter(state) {
externalParameterState.isExternalParameter = externalParameterStatus.INACTIVE;
saveExternalParameterState(externalParameterState);
},
resetExternalParameterCustomerState(state) {
externalParameterState.customer.emailAddress = null;
externalParameterState.customer.phoneNumber = null;
saveExternalParameterState(externalParameterState);
},
// RESET DEPENDENCY MUTATIONS
resetVehicleState(state) {
state.order.vehicle.year = null;
state.order.vehicle.make = null;
state.order.vehicle.model = null;
state.order.vehicle.style = null;
state.order.vehicle.carId = null;
state.order.vehicle.category = null;
state.order.vehicle.vin = null;
state.order.vehicle.imageUrl = null;
state.order.vehicle.imageVifNumber = null;
state.order.vehicle.imageColor = null;
},
resetDamageState(state) {
state.order.damage.isRepair = null;
state.order.damage.numberOfChips = null;
state.order.damage.glassToReplace = null;
},
resetRegistrationState(state) {
state.order.vehicle.registration.licensePlate = null;
},
resetGlassPartsState(state) {
state.order.lineItems.glassParts = null;
state.order.damage.partQuestionAnswers = null;
state.order.damage.moldingQuestionAnswers = null;
state.order.damage.capabilityQuestionAnswers = null;
state.applicationUser.pageData[routeData.PART_QUESTIONS.name] = null;
state.applicationUser.pageData[routeData.VEHICLE_PARTS.name] = null;
state.applicationUser.pageData[routeData.MOLDING_QUESTIONS.name] = null;
state.applicationUser.pageData[routeData.CAPABILITY_QUESTIONS.name] = null;
},
resetSchedule(state) {
state.order.schedule.date = null;
state.order.schedule.startTime = null;
state.order.schedule.endTime = null;
state.order.schedule.routeCode = null;
state.order.schedule.jobMaxMinutes = null;
state.order.schedule.jobMinMinutes = null;
//premium appointment fee used on schedule page also needs reset when schedule is reset
const supportingItems = state.order.lineItems.supportingItems;
const premiumAppointmentFeeIndex = supportingItems?.findIndex(
(item) => item.partType == PREMIUM_FEE_PART_TYPE
);
if (premiumAppointmentFeeIndex >= 0) {
supportingItems.splice(premiumAppointmentFeeIndex, 1);
state.order.lineItems.supportingItems = supportingItems;
}
},
resetState(state) {
Object.assign(state, getDefaultState());
},
// Bumps when submittedState sessionStorage is created, updated, or cleared so getters
// that read sessionStorage (coverageIsVerified, etc.) invalidate their Vuex cache.
incrementSubmittedStateRevision(state) {
state.submittedStateRevision = (state.submittedStateRevision ?? 0) + 1;
},
resetSaveSessionPromise(state) {
state.applicationUser.saveSessionPromise = null;
},
resetServiceLocationAppointmentType(state) {
state.order.serviceLocation.appointmentType = null;
},
resetServiceLocationProvider(state) {
state.order.serviceLocation.provider = {
providerNumber: null,
address: {
streetAddress: null,
city: null,
state: null,
zipCode: null,
zipCodeCtu: null,
},
};
},
resetServiceLocationMobileAddress(state) {
state.order.serviceLocation.address = null;
state.order.serviceLocation.address2 = null;
state.order.serviceLocation.city = null;
state.order.serviceLocation.state = null;
state.order.serviceLocation.isVehicleProtected = null;
},
resetPaymentMethodChoice(state) {
state.order.payment.isPia = null;
state.order.payment.piaType = null;
},
// Misc Mutations
updateStateWithOrderInformation(state, sessionInformation) {
state.order.referralNumber = sessionInformation.order.referralNumber;
state.order.referralSequenceNumber = sessionInformation.order.referralSequenceNumber;
state.order.referralDate = sessionInformation.order.referralDate;
state.order.referralCorrelationId = sessionInformation.order.referralCorrelationId;
state.order.eon = sessionInformation.order.eon;
state.order.customerPortalLoginToken = sessionInformation.order.CustomerPortalLoginToken;
state.order.isRecalAckOptIn = sessionInformation.order.isRecalAckOptIn;
state.order.workOrderId = sessionInformation.order.workOrderId
? sessionInformation.order.workOrderId
: null;
state.order.workOrderNumber = sessionInformation.order.workOrderNumber
? sessionInformation.order.workOrderNumber
: null;
state.order.lockToken = sessionInformation.order.lockToken
? sessionInformation.order.lockToken
: null;
if (state.order.vehicle.vin !== sessionInformation.order.vehicle?.vin) {
state.applicationUser.pageData[routeData.PART_QUESTIONS.name] = null;
state.applicationUser.pageData[routeData.VEHICLE_PARTS.name] = null;
state.applicationUser.pageData[routeData.MOLDING_QUESTIONS.name] = null;
state.applicationUser.pageData[routeData.CAPABILITY_QUESTIONS.name] = null;
}
state.order.vehicle = Object.assign(state.order.vehicle, {
year: sessionInformation.order.vehicle?.year,
make: sessionInformation.order.vehicle?.make,
model: sessionInformation.order.vehicle?.model,
style: sessionInformation.order.vehicle?.style,
vin: sessionInformation.order.vehicle?.vin,
carId: sessionInformation.order.vehicle?.carId,
category: sessionInformation.order.vehicle?.category,
imageUrl: sessionInformation.order.vehicle?.imageUrl,
imageVifNumber: sessionInformation.order.vehicle?.imageVifNumber,
imageColor: sessionInformation.order.vehicle?.imageVifColor,
vehicleSubType: sessionInformation.order.vehicle?.vehicleSubType,
vehicleSpecialClass: sessionInformation.order.vehicle?.vehicleSpecialClass,
isBigTruck: sessionInformation.order.vehicle?.isBigTruck,
canSafeliteService: sessionInformation.order.vehicle?.canSafeliteService,
vinRequired: sessionInformation.order.vehicle?.vinRequired,
});
state.order.damage.glassToReplace = sessionInformation.order.damage.glassToReplace;
state.order.damage.isRepair = sessionInformation.order.damage.isRepair;
state.order.damage.numberOfChips = sessionInformation.order.damage.numberOfChips;
state.order.damage.dateOfLoss = normalizeDotNetMinDate(
sessionInformation.order.damage?.dateOfLoss
);
state.order.damage.damageCause = sessionInformation.order.damage?.damageCause;
state.order.damage.partQuestionAnswers =
sessionInformation.order.damage.partQuestionAnswers;
state.order.damage.moldingQuestionAnswers =
sessionInformation.order.damage.moldingQuestionAnswers;
state.order.damage.capabilityQuestionAnswers =
sessionInformation.order.damage.capabilityQuestionAnswers;
state.order.damage.installOemGlass = sessionInformation.order.damage.installOemGlass;
state.order.lineItems.glassParts = sessionInformation.order.lineItems.glassParts;
state.order.lineItems.supportingItems = sessionInformation.order.lineItems.supportingItems;
state.order.lineItems.vaps = sessionInformation.order.lineItems.vaps ?? [];
state.order.lineItems.promos = sessionInformation.order.lineItems.promos;
state.order.lineItems.serverData = sessionInformation.order.lineItems.serverData;
state.order.payment.parentAccountNumber =
sessionInformation.order.payment.parentAccountNumber;
state.order.payment.billToAccountNumber =
sessionInformation.order.payment.billToAccountNumber;
state.order.payment.inactivePromos = sessionInformation.order.payment.inactivePromos;
state.order.payment.isClaimAndCoverage =
sessionInformation.order.payment.isClaimAndCoverage;
state.order.payment.canScheduleOnline = sessionInformation.order.payment.canScheduleOnline;
state.order.payment.accountName = sessionInformation.order.policy.insuranceCompanyName;
//Do not assign default service type once user make service type selection
if (state.order.serviceLocation.appointmentType == null) {
state.order.serviceLocation.address =
sessionInformation.order.serviceLocation.streetAddress;
state.order.serviceLocation.address2 =
sessionInformation.order.serviceLocation.streetAddress2;
state.order.serviceLocation.city = sessionInformation.order.serviceLocation.city;
state.order.serviceLocation.state = sessionInformation.order.serviceLocation.state;
state.order.serviceLocation.zipCode = sessionInformation.order.serviceLocation.zipCode;
state.order.serviceLocation.zipCodeCtu =
sessionInformation.order.serviceLocation.zipCodeCtu;
state.order.serviceLocation.appointmentType =
sessionInformation.order.serviceLocation.appointmentType;
state.order.serviceLocation.isVehicleProtected =
sessionInformation.order.serviceLocation.isVehicleProtected;
state.order.serviceLocation.provider.providerNumber =
sessionInformation.order.serviceLocation.provider?.providerNumber;
state.order.serviceLocation.provider.address.streetAddress =
sessionInformation.order.serviceLocation.provider?.address?.streetAddress;
state.order.serviceLocation.provider.address.city =
sessionInformation.order.serviceLocation.provider?.address?.city;
state.order.serviceLocation.provider.address.state =
sessionInformation.order.serviceLocation.provider?.address?.state;
state.order.serviceLocation.provider.address.zipCode =
sessionInformation.order.serviceLocation.provider?.address?.zipCode;
state.order.serviceLocation.provider.address.zipCodeCtu =
sessionInformation.order.serviceLocation.provider?.address?.zipCodeCtu;
state.order.serviceLocation.techNotes =
sessionInformation.order.serviceLocation.techNotes;
}
// if we're loading a session and we do not have a provider number yet, then set isInsurance to null so that
// a service package is not selected by default on the quote page.
if (
(sessionInformation.order.payment.isInsurance === null ||
sessionInformation.order.payment.isInsurance === undefined) &&
!sessionInformation.order.serviceLocation.provider?.providerNumber
) {
state.order.payment.isInsurance = null;
} else {
state.order.payment.isInsurance = sessionInformation.order.payment.isInsurance;
}
state.order.payment.insuranceCoverage.isVerified =
coverageStatusValue(sessionInformation?.order.insuranceCoverage.coverageStatus) ===
coverageStatus.VERIFIED
? true
: false;
state.order.payment.insuranceCoverage.coverageStatus = coverageStatusValue(
sessionInformation?.order.insuranceCoverage.coverageStatus
);
state.order.payment.insuranceCoverage.coverageSubStatus =
sessionInformation?.order.insuranceCoverage.coverageSubStatus;
state.order.payment.insuranceCoverage.coverageType = coverageTypeValue(
sessionInformation?.order.insuranceCoverage.coverageType
);
state.order.payment.insuranceCoverage.coverageVerificationType =
sessionInformation?.order.insuranceCoverage.coverageVerificationType;
state.order.customer.emailAddress = sessionInformation.order.customer.emailAddress;
state.order.customer.firstName = sessionInformation.order.customer.firstName;
state.order.customer.lastName = sessionInformation.order.customer.lastName;
state.order.customer.phoneNumber = sessionInformation.order.customer.homePhone;
state.order.customer.isSmsOptIn = sessionInformation.order.customer.isSmsOptIn;
if (sessionInformation.order.customer.address) {
state.order.customer.address = Object.assign(state.order.customer.address, {
streetAddress: sessionInformation.order.customer.address.streetAddress,
streetAddress2: sessionInformation.order.customer.address.streetAddress2,
city: sessionInformation.order.customer.address.city,
state: sessionInformation.order.customer.address.state,
zipCode: sessionInformation.order.customer.address.zipCode,
});
}
state.applicationUser.experiments = sessionInformation.applicationUser.experiments;
state.applicationUser.crmCustomerId = sessionInformation.applicationUser.crmCustomerId;
state.applicationUser.pageData = sessionInformation.applicationUser.pageData;
state.applicationUser.lastPage = sessionInformation.applicationUser.lastPage;
if (sessionInformation.applicationUser.savedSessionId) {
state.applicationUser.savedSessionId =
sessionInformation.applicationUser.savedSessionId;
}
//Do not assign default schedule details once user make schedule selection
if (state.order.schedule.date == null) {
state.order.schedule.date = sessionInformation.order.schedule?.date;
state.order.schedule.startTime = sessionInformation.order.schedule?.startTime;
state.order.schedule.endTime = sessionInformation.order.schedule?.endTime;
state.order.schedule.routeCode = sessionInformation.order.schedule?.routeCode;
state.order.schedule.jobMaxMinutes = sessionInformation.order.schedule?.jobMaxMinutes;
state.order.schedule.jobMinMinutes = sessionInformation.order.schedule?.jobMinMinutes;
}
state.order.policy.currentDeductible = sessionInformation.order.policy?.currentDeductible;
state.order.policy.originalDeductible = sessionInformation.order.policy?.originalDeductible;
state.order.policy.additionalAuthFlag = sessionInformation.order.policy?.additionalAuthFlag;
state.order.policy.isItac =
coverageTypeValue(sessionInformation?.order.insuranceCoverage.coverageType) ===
coverageType.ITAC
? true
: false;
state.order.policy.policyNumber = sessionInformation.order.policy?.policyNumber;
state.order.payment.insuranceCoverage.claimNumber =
sessionInformation.order.insuranceCoverage?.claimNumber;
state.order.policy.insuranceCompanyName =
sessionInformation.order.policy?.insuranceCompanyName;
state.order.policy.isNoComp =
coverageTypeValue(sessionInformation?.order.insuranceCoverage.coverageType) ===
coverageType.NOCOMP
? true
: false;
sessionInformation.order.policy?.noComprehensive;
},
updateExperiments(state, experiments) {
state.applicationUser.experiments = experiments;
},
updateTriggeredSiteEntry(state, wasSiteEntryTriggered) {
state.applicationUser.triggeredSiteEntry = wasSiteEntryTriggered;
},
updateAffiliateCookies(state, affiliateCookies) {
state.applicationUser.affiliateCookies = affiliateCookies;
},
updateHasTriggeredError(state, hasTriggeredError) {
state.applicationUser.hasAlreadyTriggeredError = hasTriggeredError;
},
updateIdempotencyKey(
state,
{ idempotencyKey, referralCorrelationId, totalInCents, expiryTime }
) {
state.idempotencyKeyFields.idempotencyKey = idempotencyKey;
state.idempotencyKeyFields.referralCorrelationId = referralCorrelationId;
state.idempotencyKeyFields.totalInCents = totalInCents;
state.idempotencyKeyFields.expiryTime = expiryTime;
},
};
// Export Getters
export const getters = {
vehicle: (state) => state.order.vehicle,
eventBusItem: (state) => (eventCategory, eventSubCategory) => {
const matchedEvent = state.applicationUser.eventBus.find(
({ category, subCategory }) =>
category === eventCategory && subCategory === eventSubCategory
);
return matchedEvent !== undefined ? matchedEvent.eventValue : undefined;
},
eventBus: (state) => state.applicationUser.eventBus,
damage: (state) => state.order.damage,
hasExactlyOneChip: (state) => {
return state.order.damage?.numberOfChips === 1;
},
hasAnyNonWindshieldGlassParts: (state) => {
const nonWindshieldItems = state.order.damage.glassToReplace?.filter(
(glassToReplace) => glassToReplace.glassLocation != "Windshield"
);
return !!nonWindshieldItems?.length;
},
coverageIsVerified: (state) => {
state.submittedStateRevision;
let order;
if (window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) !== null) {
order = JSON.parse(
window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE)
).order;
} else {
order = state.order;
}
if (
order.payment?.insuranceCoverage?.isVerified &&
order.policy?.currentDeductible != 9999 &&
order.policy?.currentDeductible != 7777
) {
return true;
}
return false;
},
isMobileAppointment: (state) => {
return state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE;
},
isDropOffAppointment: (state) => {
return state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF;
},
isOvernightDropOffAppointment: (state) => {
return state.order.schedule.routeCode?.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF);
},
isRecalibrationOnOrder: (state) => {
return getHasRecalibrationPart(state);
},
isRecalibrationOnSubmittedState: (state) => {
state.submittedStateRevision;
if (window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) !== null) {
return getHasRecalibrationPart({
order: JSON.parse(
window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE)
).order,
});
}
return false;
},
shouldHideRecalibration: (state) => {
state.submittedStateRevision;
if (window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) !== null) {
state = JSON.parse(
window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE)
);
}
let order = state.order;
let applicationUser = state.applicationUser;
if (order.payment.isInsurance) {
return false;
}
return (
hasSettingEqualTo(
experimentSettings.RECAL_PRICE_REMOVE,
"true",
getExperimentSettingsFromExperimentList(applicationUser.experiments)
) && getters.isRecalibrationOnOrder(state)
);
},
areRearWipersOnOrder: (state) => {
return !!state.order.lineItems.vaps?.some(
(vap) => vap.partType.toUpperCase() === partTypeStrings.REAR_WIPER.toUpperCase()
);
},
scheduleDisplayText: (state) => {
const dateModel = convertDateStringToDate(state.order.schedule.date);
const readableDate = dateModel?.toLocaleDateString("en-us", {
weekday: "long",
month: "long",
day: "numeric",
year: "numeric",
});
const readableStartTime = militaryToTwelveHourTime(state.order.schedule.startTime);
const readableEndTime = militaryToTwelveHourTime(state.order.schedule.endTime);
const readableDuration = getDisplayTextForDurationLength(
state.order.schedule.jobMinMinutes,
state.order.schedule.jobMaxMinutes
);
return {
date: readableDate,
startTime: readableStartTime,
endTime: readableEndTime,
duration: readableDuration,
};
},
lineItems: (state) => state.order.lineItems,
pageData: (state) => (page) => {
return state.applicationUser.pageData[page];
},
bailoutCode: (state) => state.applicationUser.pageData.bailout?.bailoutCode,
applicationUser: (state) => state.applicationUser,
order: (state) => state.order,
payment: (state) => state.order.payment,
policy: (state) => state.order.policy,
experimentOrder: (state) => {
return {
funnelVehicleYear: state.order.vehicle.year,
funnelVehicleMake: state.order.vehicle.make,
funnelVehicleModel: state.order.vehicle.model,
funnelVehicleStyle: state.order.vehicle.style,
funnelIsRepair: state.order.damage.isRepair,
funnelNumberOfChips: state.order.damage.numberOfChips,
funnelCarId: state.order.vehicle.carId,
funnelServiceCity: state.order.serviceLocation.city,
funnelServiceState: state.order.serviceLocation.state,
funnelServiceZipCode: state.order.serviceLocation.zipCode,
funnelServiceZipCodeCtu: state.order.serviceLocation.zipCodeCtu,
funnelPolicyIsItac: state.order.policy.isItac ? "true" : "false",
funnelPolicyIsNoComp: state.order.policy.isNoComp ? "true" : "false",
funnelProviderNumber: state.order.serviceLocation.provider.providerNumber,
funnelParentAccountNumber: state.order.payment.parentAccountNumber,
funnelReferralType: state.order.payment.isInsurance ? "INSURANCE" : "CASH QUOTE",
funnelIsCoverageVerified: state.order.payment.insuranceCoverage.isVerified,
funnelHasRecalibrationPart: getHasRecalibrationPart(state),
funnelSelectedMultiGlass: state.order.damage.glassToReplace?.length > 1,
funnelSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.WINDSHIELD),
funnelSelectedBackGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.REAR),
funnelSelectedDriverSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.DRIVER),
funnelSelectedPassengerSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.PASSENGER),
funnelOrderPartNumbers: [
...getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.lineItems.glassParts,
"partNumber"
),
...getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.lineItems.supportingItems,
"partNumber"
),
...getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.lineItems.vaps,
"partNumber"
),
],
funnelOrderPartTypes: [
...getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.lineItems.glassParts,
"recalibrationType"
),
],
};
},
experimentSettings: (state) =>
getExperimentSettingsFromExperimentList(state.applicationUser.experiments),
isVerifiedAndDeductibleZeroConfirmed: (state) => {
// used in CMS on /payment-method in Header Sub Text, for FunnelSubHeaderWidget on cart pages
if (
state.order.policy.currentDeductible === 0 &&
getters.coverageIsVerified(state) &&
!state.order.policy.isNoComp
) {
return true;
}
return false;
},
isItacOrNoComp: (state) => {
// used in CMS on /payment-method in Header Sub Text, for FunnelSubHeaderWidget on cart pages
if (state.order.policy.isNoComp || state.order.policy.isItac) {
return true;
} else {
return false;
}
},
requiresVerifiedRedirecting: (state) => {
return state.order?.referralNumber?.length === 6;
},
externalParameterState: (state) => externalParameterState,
externalParameterVehicle: (state) => externalParameterState?.vehicle,
externalParameterDamage: (state) => externalParameterState?.vehicleDamage,
externalParameterQuote: (state) => externalParameterState?.quote,
externalParameterServiceZip: (state) => externalParameterState?.serviceZip,
externalParameterEstimate: (state) => externalParameterState?.estimate,
externalParameterCustomer: (state) => externalParameterState?.customer,
isExternalParameter: (state) => externalParameterState?.isExternalParameter,
emailOrSms: (state) => {
const email =
externalParameterState.customer.emailAddress ?? state.order.customer.emailAddress;
const phone =
externalParameterState.customer.phoneNumber ?? state.order.customer.phoneNumber;
if (!phone && !email) {
return null;
}
if (phone && !email) {
return phone;
}
if (email && !phone) {
return email;
}
// if we're here, then we have both email and phone so get the value from pageData to reflect what they entered on the page.
// if they didn't enter anything on the page default to email
return (
state.applicationUser.pageData[routeData.SERVICE_ZIP.name]?.emailOrSmsValue ??
state.order.customer.emailAddress
);
},
isIdempotencyKeyValid: (state) => {
if (!state.idempotencyKeyFields?.idempotencyKey) {
return false;
}
const referralCorrelationId = state.order?.referralCorrelationId;
if (
!referralCorrelationId ||
referralCorrelationId !== state.idempotencyKeyFields?.referralCorrelationId
) {
return false;
}
const total = getAmountDue(state.order?.lineItems);
const totalInCents = Math.round(total * 100);
if (totalInCents !== state.idempotencyKeyFields?.totalInCents) {
return false;
}
const currentTime = new Date();
const expiryTime = new Date(state.idempotencyKeyFields.expiryTime);
if (!expiryTime || expiryTime.getTime() < currentTime.getTime()) {
return false;
}
// If all checks pass, then the key is valid.
return true;
},
};
// Export Actions
export const actions = {
// Vehicle API Actions
getVehicleYears(context, { pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleYears.method,
endpoint: endpoints.GetVehicleYears.url,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVehicleByYmms(context, { payload: { year, make, model, style }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.LookupVehicleByYmms.method,
endpoint: `${endpoints.LookupVehicleByYmms.url}/${year}/${make}/${model}/${style}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVehicleByVin(context, { payload: { vin }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.LookupVehicleByVin.method,
endpoint: endpoints.LookupVehicleByVin.url,
payload: {
vin: vin, // EX "1J4GW58S4XC541166"
logEnabled: context.getters.applicationUser.loggingOption,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVinByPlate(context, { payload: { licensePlate, licenseState }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.LookupVinByPlate.method,
endpoint: endpoints.LookupVinByPlate.url,
payload: {
licensePlate: licensePlate,
licenseState: licenseState,
logEnabled: context.getters.applicationUser.loggingOption,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVinByAddress(
context,
{
payload: { licenseLastName, licenseStreetAddress, licenseZip, licenseState },
pageNameToLog,
}
) {
return globalMethods.callHttpClient({
method: endpoints.LookupVinByAddress.method,
endpoint: endpoints.LookupVinByAddress.url,
payload: {
licenseLastName: licenseLastName,
licenseStreetAddress: licenseStreetAddress,
licenseZip: licenseZip,
licenseState: licenseState,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVinByImage(context, { payload, pageNameToLog }) {
const image = payload;
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = (e) => {
resolve(reader.result);
};
reader.readAsDataURL(image);
}).then((result) => {
const components = result.split(",");
const contentType = image.type;
const imageBase64 = components[1];
const data = {
imageData: imageBase64,
contentType: contentType,
fileName: image.name,
};
return globalMethods.callHttpClient({
method: endpoints.LookupVinByImage.method,
endpoint: endpoints.LookupVinByImage.url,
payload: data,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
});
},
isVinByAddressPermissible(context, { payload: { zip }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.IsVinByAddressPermissible.method,
endpoint: `${endpoints.IsVinByAddressPermissible.url}?zipcode=${zip}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getVehicleMakes(context, { payload: { year }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleMakes.method,
endpoint: `${endpoints.GetVehicleMakes.url}/${year}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getVehicleModels(context, { payload: { year, make }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleModels.method,
endpoint: `${endpoints.GetVehicleModels.url}/${year}/${make}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getVehicleStyles(context, { payload: { year, make, model }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleStyles.method,
endpoint: `${endpoints.GetVehicleStyles.url}/${year}/${make}/${model}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getVehicle(context, { payload: { year, make, model, style }, pageNameToLog }) {
return globalMethods
.callHttpClient({
methods: endpoints.GetVehicle.method,
endpoint: `${endpoints.GetVehicle.url}/${year}/${make}/${model}/${style}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
})
.then((response) => {
return response;
});
},
getDamageOptions(context, { payload: { carId }, pageNameToLog }) {
return globalMethods.callHttpClient({
methods: endpoints.GetDamageOptions.method,
endpoint: `${endpoints.GetDamageOptions.url}/${carId}`,
payload: {},
additionalSuccessEventDataHandler: (response) =>
"QueryStringZip: " + getQuerystringParameter(queryStrings.ZIP_CODE),
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
validateZip(context, { payload: { zip }, pageNameToLog }) {
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
return globalMethods.callHttpClient({
methods: endpoints.ValidateZip.method,
endpoint: `${endpoints.ValidateZip.url}/${zip}/${damageType}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getClosestApplicableShops(context, { payload: { zip, carId }, pageNameToLog }) {
return globalMethods.callHttpClient({
methods: endpoints.ClosestApplicableShops.method,
endpoint: `${endpoints.ClosestApplicableShops.url}/${zip}/${carId}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
// Dependency Actions
resetVehicleStateAndDependencies(context) {
context.commit(storeMutations.RESET_VEHICLE_STATE);
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
},
resetDamageAndDependencies(context) {
context.commit(storeMutations.RESET_DAMAGE_STATE);
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
context.commit(storeMutations.UPDATE_VAPS, null);
},
resetRegistrationAndDependencies(context) {
context.commit(storeMutations.RESET_REGISTRATION_STATE);
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
},
resetPartsAndDependencies(context) {
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
context.commit(storeMutations.UPDATE_VAPS, null);
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
},
resetServiceLocationAndDependencies(context) {
context.commit(storeMutations.RESET_SERVICE_LOCATION_APPOINTMENT_TYPE);
context.commit(storeMutations.RESET_SERVICE_LOCATION_PROVIDER);
context.commit(storeMutations.RESET_SCHEDULE);
context.commit(storeMutations.RESET_PAYMENT_METHOD_CHOICE);
},
resetState(context) {
context.commit(storeMutations.RESET_STATE);
},
resetSaveSessionPromise(context) {
context.commit(storeMutations.RESET_SAVE_SESSION_PROMISE);
},
getPageData(context, { pageName }) {
return globalMethods.callHttpClient({
method: endpoints.GetPageData.method,
endpoint: endpoints.GetPageData.url(
applicationConfig.APPLICATION_ABBREVIATION,
pageName
),
payload: {},
logApiCall: true,
pageNameToLog: pageName,
});
},
// Analytics Actions
logExperimentExposureAndUpdateStore(
context,
{ payload: { userId, deviceId, sessionKey, pageName, experiment }, pageNameToLog }
) {
const experiments = deepClone(context.getters.applicationUser.experiments);
const experimentToMarkAsExposed = experiments.find((ex) => {
return (
ex.universeId == experiment.universeId &&
ex.testId == experiment.testId &&
ex.variationId == experiment.variationId &&
ex.assignmentId == experiment.assignmentId
);
});
if (experimentToMarkAsExposed) {
experimentToMarkAsExposed.isExposed = true;
}
context.commit(storeMutations.UPDATE_EXPERIMENTS, experiments);
return globalMethods.callHttpClient({
method: endpoints.LogExperimentExposureIfAssigned.method,
endpoint: endpoints.LogExperimentExposureIfAssigned.url,
payload: {
experimentForLogging: {
userId: userId,
deviceId: deviceId,
experimentUniverseId: experiment.universeId,
experimentUniverseName: experiment.universeName,
experimentTestId: experiment.testId,
experimentTestName: experiment.testName,
experimentVariationId: experiment.variationId,
experimentVariationName: experiment.variationName,
enabled: experiment.isActive,
isExposed: experiment.isExposed,
userPartitionNumber: experiment.userPartitionNumber,
assignmentId: experiment.assignmentId,
sessionKey: sessionKey,
pageName: pageName,
},
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
// Location API Actions
getAlertReasonsByCtu(context, { payload: { ctu }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetAlertReasons.method,
endpoint: `${endpoints.GetAlertReasons.url}/${ctu}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
// Misc Actions
updateStoreWithSaveSessionResponse(
context,
{
referralNumber,
referralSequenceNumber,
referralDate,
referralCorrelationId,
eon,
parentAccountNumber,
savedSessionId,
crmCustomerId,
workOrderNumber,
workOrderId,
customerPortalLoginToken,
lockToken,
settledTenderAmount,
billToAccountNumber,
}
) {
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
context.commit(storeMutations.UPDATE_REFERRAL_SEQUENCE_NUMBER, referralSequenceNumber);
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
context.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, referralCorrelationId);
context.commit(storeMutations.UPDATE_EON, eon);
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber);
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
context.commit(storeMutations.WORK_ORDER_NUMBER, workOrderNumber);
context.commit(storeMutations.WORK_ORDER_ID, workOrderId);
context.commit(storeMutations.LOCK_TOKEN, lockToken);
context.commit(storeMutations.Customer_Portal_Login_Token, customerPortalLoginToken);
context.commit(storeMutations.UPDATE_SETTLED_TENDER_AMOUNT, settledTenderAmount);
context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber);
},
logPageView(
context,
{
userId,
sessionKey,
pageName,
sessionId,
action,
event,
shouldUseSessionId,
experimentsForUser,
referralSequenceNumber,
parentAccountNumber,
}
) {
if (!pageName) {
return;
}
var payload = {
userId: userId,
sessionKey: sessionKey,
sessionId: sessionId,
pageName: pageName,
applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME,
action: action,
event: event,
shouldUseSessionId: shouldUseSessionId,
experimentsForUser: experimentsForUser,
referralSequenceNumber: referralSequenceNumber,
parentAccountNumber:
parentAccountNumber ?? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
};
return globalMethods
.callHttpClient({
method: endpoints.LogPageView.method,
endpoint: endpoints.LogPageView.url,
payload: payload,
logApiCall: false,
})
.then((response) => {
return response;
});
},
logCustomEvent(
context,
{
userId,
sessionKey,
pageName,
sessionId,
category,
action,
label,
value,
shouldUseSessionId,
experimentsForUser,
referralSequenceNumber,
parentAccountNumber,
}
) {
if (!pageName || !category) {
return;
}
var payload = {
userId: userId,
sessionKey: sessionKey,
sessionId: sessionId,
pageName: pageName,
applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME,
category: category,
action: action,
label: label,
value: value,
shouldUseSessionId: shouldUseSessionId,
experimentsForUser: experimentsForUser,
referralSequenceNumber: referralSequenceNumber,
parentAccountNumber:
parentAccountNumber ?? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
};
return globalMethods
.callHttpClient({
method: endpoints.LogCustomEvent.method,
endpoint: endpoints.LogCustomEvent.url,
payload: payload,
logApiCall: false,
})
.then((response) => {
return response;
});
},
initializeSession(context, { userId, deviceId, sessionId, userAgent, referrer }) {
var payload = {
applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME,
userId: userId,
deviceId: deviceId,
sessionId: sessionId,
userAgent: userAgent,
operatorId: "WEB",
userName: "SafeliteConceptFunnel",
referrer: referrer,
clientData: window.location.search,
};
return globalMethods
.callHttpClient({
method: endpoints.InitializeSession.method,
endpoint: endpoints.InitializeSession.url,
payload: payload,
logApiCall: false,
})
.then((response) => {
return response;
});
},
logPartQuestions(
context,
{ eon, ctu, workOrderId, workOrderNumber, carId, glassLocation, partQuestions, userAgent }
) {
var payload = {
applicationName: applicationConfig.APPLICATION_NAME,
eon: eon,
ctu: ctu,
workOrderId: workOrderId,
workOrderNumber: workOrderNumber,
carId: carId,
glassLocation: glassLocation,
partQuestions: partQuestions,
userAgent: navigator.userAgent,
};
return globalMethods.callHttpClient({
method: endpoints.LogPartQuestions.method,
endpoint: endpoints.LogPartQuestions.url,
payload: payload,
});
},
logFmgSessionData(
context,
{
currentPage,
sid,
deviceId,
fmgSessionId,
skey,
userId,
carId,
vehicleYear,
vehicleMake,
vehicleModel,
vehicleStyle,
hasVin,
cashOrInsuranceAccountType,
damageType,
productType,
eon,
referralNumber,
referralSequenceNumber,
referralDate,
workOrderNumber,
workOrderId,
isPia,
piaType,
parentAccountNumber,
billToAccountNumber,
settledTenderAmount,
recalRequired,
recalType,
serviceZipCode,
providerCtu,
appointmentDate,
serviceType,
promoCodes,
hasTechnicianNotes,
paymentMethod,
isTextingOptedIn,
isEarlyBird,
insuranceCo,
deductible,
isVerified,
coverageStatus,
coverageSubStatus,
isNoComp,
isItac,
isClaimAndCoverage,
vinRequired,
installOemGlass,
subTotalPrice,
totalPrice,
userAgent,
cashPriceSubTotal,
bailoutCode,
}
) {
var payload = {
currentPage: currentPage,
sid: sid,
deviceId: deviceId,
fmgSessionId: fmgSessionId,
skey: skey,
userId: userId,
carId: carId,
vehicleYear: vehicleYear,
vehicleMake: vehicleMake,
vehicleModel: vehicleModel,
vehicleStyle: vehicleStyle,
hasVin: hasVin,
cashOrInsuranceAccountType: cashOrInsuranceAccountType,
isVerified: isVerified,
coverageStatus: coverageStatus,
coverageSubStatus: coverageSubStatus,
damageType: damageType,
productType: productType,
eon: eon,
referralNumber: referralNumber,
referralSequenceNumber: referralSequenceNumber,
referralDate: referralDate,
workOrderNumber: workOrderNumber,
workOrderId: workOrderId,
isPia: isPia,
piaType: piaType,
parentAccountNumber: parentAccountNumber,
settledTenderAmount: settledTenderAmount,
recalRequired: recalRequired,
recalType: recalType,
serviceZipCode: serviceZipCode,
providerCtu: providerCtu,
appointmentDate: appointmentDate,
serviceType: serviceType,
promoCodes: promoCodes,
hasTechnicianNotes: hasTechnicianNotes,
paymentMethod: paymentMethod,
isTextingOptedIn: isTextingOptedIn,
isEarlyBird: isEarlyBird,
insuranceCo: insuranceCo,
deductible: deductible,
isNoComp: isNoComp,
isItac: isItac,
isClaimAndCoverage: isClaimAndCoverage,
vinRequired: vinRequired,
installOemGlass: installOemGlass,
subTotalPrice: subTotalPrice,
totalPrice: totalPrice,
userAgent: userAgent,
cashPriceSubTotal: cashPriceSubTotal,
billToAccountNumber: billToAccountNumber,
bailoutCode: bailoutCode,
};
return globalMethods.callHttpClient({
method: endpoints.LogFmgSessionData.method,
endpoint: endpoints.LogFmgSessionData.url,
payload: payload,
logApiCall: false,
});
},
// Misc Actions
setReferralInformation(context, { referralNumber, referralDate, referralCorrelationId, eon }) {
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
context.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, referralCorrelationId);
context.commit(storeMutations.UPDATE_EON, eon);
},
GetExperimentsByUser(context, { userId }) {
return globalMethods.callHttpClient({
method: endpoints.GetExperimentsByUser.method,
endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`,
payload: {},
});
},
async runExperimentsForTrigger(
context,
{ payload: { deviceId, triggerEvent, triggerValue }, pageNameToLog }
) {
if (triggerEvent == experimentTriggers.SITE_ENTRY) {
context.commit(storeMutations.UPDATE_TRIGGERED_SITE_ENTRY, true);
}
var payload = {
applicationName: applicationConfig.APPLICATION_NAME,
deviceId: deviceId,
triggerEvent: triggerEvent,
triggerValue: triggerValue,
experimentOrder: context.getters.experimentOrder,
};
const response = await globalMethods.callHttpClient({
method: endpoints.RunExperimentsForTrigger.method,
endpoint: endpoints.RunExperimentsForTrigger.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
context.commit(storeMutations.UPDATE_EXPERIMENTS, response.data.experiments);
},
async forceExperiments(
context,
{ payload: { deviceId, queryStringExperiments }, pageNameToLog }
) {
var payload = {
applicationName: applicationConfig.APPLICATION_NAME,
deviceId: deviceId,
queryStringExperiments: queryStringExperiments,
};
const response = await globalMethods.callHttpClient({
method: endpoints.ForceExperiments.method,
endpoint: endpoints.ForceExperiments.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getEvoxImage(context, { relativeUrl }) {
return globalMethods.callHttpClient({
method: endpoints.GetPageData.method,
endpoint: relativeUrl,
payload: {},
});
},
// PartsOrQuestions API Actions
async getPartsOrQuestions(context, { pageNameToLog }) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
const order = context.state.order;
const carId = vehicle.carId;
const glassArray = damage.glassToReplace;
const zipCode = order.serviceLocation.zipCode;
const vin = vehicle.vin;
const serviceType = damage.isRepair ? "Repair" : "Install";
const parentAccountNumber = context.getters.payment.parentAccountNumber;
const referralSeqNumber = order.referralSequenceNumber;
// create a new array to avoid mutating state
const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray);
const partsOrQuestionsEndpoint = vehicle.vinRequired
? endpoints.GetPartsOrQuestionsV2
: endpoints.GetPartsOrQuestions;
const response = await globalMethods
.callHttpClient({
method: partsOrQuestionsEndpoint.method,
endpoint: partsOrQuestionsEndpoint.url,
payload: {
carId: carId,
glassPieces: glassArrayForPayload,
zip: zipCode,
vin: vin,
serviceType: serviceType,
referralSeqNumber: referralSeqNumber,
parentAccountNumber: parentAccountNumber,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
})
.catch((error) => {
if (error.status == 500) {
return { PartNotFound: true };
}
});
// Triggers bailout
if (response.PartNotFound) {
return response;
}
// Check if we only have MISC parts to trigger bailout
const miscPartsResponse = checkIfMiscParts(response.data.partsOrQuestions);
if (miscPartsResponse.PartNotFound) {
return miscPartsResponse;
}
// Flatten location and name properties
response.data.partsOrQuestions = convertGlassPieceNamingFromApi(
response.data.partsOrQuestions
);
return response;
},
// Parts API Actions
async getParts(context, { pageNameToLog }) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
const order = context.state.order;
const payment = context.getters.payment;
const carId = vehicle.carId;
const glassArray = damage.glassToReplace;
const resultsArray = damage.partQuestionAnswers;
const zipCode = order.serviceLocation.zipCode;
const vin = vehicle.vin;
const serviceType = order.serviceLocation?.appointmentType;
const referralSeqNumber = order.referralSequenceNumber;
const parentAccountNumber = payment.parentAccountNumber;
// create a new array to avoid mutating state
const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray);
const resultsArrayForPayload = convertResultsForApi(resultsArray);
const response = await globalMethods.callHttpClient({
method: endpoints.GetParts.method,
endpoint: endpoints.GetParts.url,
payload: {
carId: carId,
glassPieces: glassArrayForPayload,
answerResults: resultsArrayForPayload,
zip: zipCode,
vin: vin,
serviceType: serviceType,
referralSeqNumber: referralSeqNumber,
parentAccountNumber: parentAccountNumber,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
// Flatten location and name properties
response.data.glassPieceParts = convertGlassPieceNamingFromApi(
response.data.glassPieceParts
);
return response;
},
// Parts API Actions
async getOemAfterMarketParts(context, { pageNameToLog }) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
const order = context.state.order;
const carId = vehicle.carId;
const glassArray = damage.glassToReplace;
const resultsArray = damage.partQuestionAnswers;
const zipCode = order.serviceLocation.zipCode;
const vin = vehicle.vin;
const make = vehicle.make;
const serviceType = order.serviceLocation?.appointmentType;
const referralSeqNumber = order.referralSequenceNumber;
const parentAccountNumber = applicationConfig.CASH_PARENT_ACCOUNT_NUMBER;
const oemEndorsementFlag = order.damage.installOemGlass || false;
// create a new array to avoid mutating state
const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray);
const resultsArrayForPayload = convertResultsForApi(resultsArray);
const response = await globalMethods.callHttpClient({
method: endpoints.GetOemAfterMarketParts.method,
endpoint: endpoints.GetOemAfterMarketParts.url,
payload: {
carId: carId,
glassPieces: glassArrayForPayload,
answerResults: resultsArrayForPayload,
zip: zipCode,
vin: vin,
serviceType: serviceType,
referralSeqNumber: referralSeqNumber,
make: make,
parentAccountNumber: parentAccountNumber.toString(),
oemEndorsementFlag: oemEndorsementFlag,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
// Flatten location and name properties
if (response?.data?.glassPieceParts) {
response.data.glassPieceParts = convertGlassPieceNamingFromApi(
response.data.glassPieceParts
);
}
return response;
},
async getWipers(context, { payload, pageNameToLog }) {
const carId = payload.carId;
const accountNumber = payload.accountNumber;
const response = await globalMethods
.callHttpClient({
method: endpoints.GetWipers.method,
endpoint: `${endpoints.GetWipers.url}/${carId}/${accountNumber}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
})
.catch((error) => {
// The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow
return [];
});
syncLineItemIds(response.data, context.getters.order.lineItems.vaps);
return response;
},
async getRainRepel(context, { pageNameToLog }) {
const response = await globalMethods.callHttpClient({
method: endpoints.GetRainRepel.method,
endpoint: endpoints.GetRainRepel.url,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
syncLineItemIds([response.data], context.getters.order.lineItems.vaps);
return response;
},
getMobileFeePart(
context,
{ payload: { serviceZipCode, serviceZipCodeCtu, mobileProviderNumber }, pageNameToLog }
) {
const serviceType = context.getters.damage.isRepair ? "Repair" : "Install";
const facilityType = "Mobile";
const parentAccountNumber = context.getters.payment.parentAccountNumber;
const billToAccountNumber = context.getters.payment.billToAccountNumber
? context.getters.payment.billToAccountNumber
: applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER;
const order = context.getters.order;
const coverageStatus = coverageStatusEnum(order.payment?.insuranceCoverage?.coverageStatus);
const coverageType = coverageTypeEnum(order.payment?.insuranceCoverage?.coverageType);
const isItacOptimized = order.policy?.isItac ?? false;
const zipCode =
serviceZipCode ??
order.serviceLocation?.provider?.address?.zipCode ??
order.serviceLocation?.zipCode;
var providerNumber =
mobileProviderNumber ??
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}`;
const recalPartNumbers = getRecalPartNumbers(order.lineItems?.glassParts);
const carId = order.vehicle?.carId;
if (recalPartNumbers && recalPartNumbers.length > 0 && carId) {
let additionalQueryParams = ``;
for (let i = 0; i < recalPartNumbers.length; i++) {
additionalQueryParams += `&partNumbers[${i}]=${recalPartNumbers[i]}`;
}
additionalQueryParams += `&carId=${carId}`;
endPoint += additionalQueryParams;
}
if (coverageStatus) {
endPoint = `${endPoint}&coverageStatus=${coverageStatus}`;
}
if (coverageType) {
endPoint = `${endPoint}&coverageType=${coverageType}`;
}
return globalMethods.callHttpClient({
method: endpoints.GetMobileFeePart.method,
endpoint: endPoint,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
async getPricingByDayPart(context, { pageNameToLog }) {
return await globalMethods
.callHttpClient({
method: endpoints.GetPricingByDayPart.method,
endpoint: endpoints.GetPricingByDayPart.url,
logApiCall: true,
pageNameToLog: pageNameToLog,
})
.then((response) => {
return response;
});
},
getServiceabilityDetails(context, { payload: { serviceZipCode }, pageNameToLog }) {
const flattenedLineItemsWithChildParts = getFlattenedArrayOfLineItemsWithChildParts(
context.getters.order.lineItems.glassParts
);
const lineItemsList = flattenedLineItemsWithChildParts
.map((item) => item.partNumber)
.join(",");
const vehicle = context.getters.vehicle;
const carId = vehicle.carId;
const damage = context.getters.damage;
const parentAccountNumber =
context.getters.order.payment.parentAccountNumber ??
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER;
var endPoint = `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&parentAccountNumber=${parentAccountNumber}&isRepair=${damage.isRepair}`;
if (lineItemsList) {
endPoint += `&lineItems=${lineItemsList}`;
}
return globalMethods.callHttpClient({
method: endpoints.GetServiceabilityDetails.method,
endpoint: endPoint,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getProviders(context, { payload: { serviceZipCode }, pageNameToLog }) {
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
const accountNumber =
context.getters.order.payment.parentAccountNumber ??
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER;
const carId = context.getters.order.vehicle.carId;
const partsWithRecal = getTopLevelPartsWithRecal(
context.getters.order.lineItems.glassParts
);
const windshieldPartWithRecal = partsWithRecal?.length > 0 ? partsWithRecal[0] : null;
const shopRadiusInMiles = 100;
let url = `${endpoints.GetProviders.url}/${serviceZipCode}/${damageType}/${shopRadiusInMiles}/${accountNumber}/true/${carId}`;
if (windshieldPartWithRecal) {
url += `/${windshieldPartWithRecal.partNumber}`;
}
//heavy truck vehicle
url += `/${context.getters.order.vehicle.isBigTruck}`;
return globalMethods.callHttpClient({
method: endpoints.GetProviders.method,
endpoint: url,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getSupportingItems(context, { pageNameToLog }) {
const glassPartsArray = context.getters.lineItems.glassParts ?? [];
const carId = context.getters.vehicle.carId;
const isRepair = context.getters.damage.isRepair;
const numberOfChips = context.getters.damage.numberOfChips;
const apptType = context.getters.order?.serviceLocation?.appointmentType;
return globalMethods.callHttpClient({
method: endpoints.GetSupportingItems.method,
endpoint: endpoints.GetSupportingItems.url,
payload: {
carId: carId,
damageType: isRepair ? "Repair" : "Replace",
parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
parts: glassPartsArray,
numberOfRepairChips: isRepair ? numberOfChips : 0,
providerNumber: context.getters.order.serviceLocation.zipCodeCtu,
facilityType:
apptType && apptType.trim() !== "" ? apptType : AppointmentTypeStrings.IN_SHOP,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getCapabilityQuestions(context, { payload: { carId, partNumber }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetCapabilityQuestions.method,
endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
async submitDonationPartToSV2(
context,
{ payload: { selectedItemNumber, submittedOrder }, pageNameToLog }
) {
const state = JSON.parse(
window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE)
);
const order = state.order;
const payload = {
selectedItemNumber: selectedItemNumber,
savedSessionId: state.applicationUser.savedSessionId,
paymentInfo: {
parentAccountNumber: order.payment.parentAccountNumber,
billToAccountNumber: order.payment.billToAccountNumber,
providerNumber: order.serviceLocation.provider.providerNumber,
carId: order.vehicle.carId,
make: order.vehicle.make,
model: order.vehicle.model,
year: order.vehicle.year,
eon: order.eon,
zipCode: order.serviceLocation.zipCode,
state: order.serviceLocation.state,
referralNumber: order.referralNumber,
referralDate: order.referralDate,
referralSequenceNumber: order.referralSequenceNumber,
serviceZipCode: order.serviceLocation.zipCode,
isReplacement: !order.damage.isRepair,
deductible: order.policy.currentDeductible,
coverageStatus: order.payment.insuranceCoverage.coverageStatus,
coverageSubStatus: order.payment.insuranceCoverage.coverageSubStatus,
serverData: order.lineItems.serverData,
},
};
const response = await globalMethods.callHttpClient({
method: endpoints.AddDonationPart.method,
endpoint: endpoints.AddDonationPart.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
return response.data;
},
getPartFromCapabilityQuestionAnswer(context, { payload, pageNameToLog }) {
const glassLocation = payload;
const pageData = context.getters.pageData(routeData.CAPABILITY_QUESTIONS.name);
const part = pageData.partsOrQuestions.find((x) => x.glassLocation === glassLocation)
.parts[0];
const capabilityQuestionAnswers = context.getters.damage.capabilityQuestionAnswers;
const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find(
(x) => x.glassLocation === glassLocation
);
return globalMethods.callHttpClient({
method: endpoints.GetPartFromCapabilityAnswer.method,
endpoint: endpoints.GetPartFromCapabilityAnswer.url,
payload: {
part,
capabilityAnswerResults: capabilityQuestionAnswersForPart,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getShopTimeSlots(
context,
{ payload: { startDate, endDate, shopAppointmentType, providerNumber }, pageNameToLog }
) {
const order = context.state.order;
const vehicle = context.state.order.vehicle;
const payment = context.state.order.payment;
const lineItems = getFlattenedLineItemsWithGlassPartTag(order.lineItems);
const glassPieces = order.damage.glassToReplace
? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace)
: [];
var payload = {
zipCode: order.serviceLocation.provider.zipCode,
providerNumber: providerNumber,
startDate: startDate,
endDate: endDate,
shopAppointmentType: shopAppointmentType,
applicationName: applicationConfig.APPLICATION_NAME,
parentAccountNumber: payment.parentAccountNumber,
carId: vehicle.carId,
lineItems: lineItems,
glassPieces: glassPieces,
eon: order.eon,
billToAccountNumber: context.getters.payment.billToAccountNumber,
coverage: {
status: payment.insuranceCoverage.coverageStatus,
deductible: order.policy.currentDeductible,
additionalAuthFlag: order.policy.additionalAuthFlag,
},
partSelection: {
hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length,
hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length,
hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length,
hasManuallySelectedParts:
!!context.state.applicationUser.pageData["vehicle-parts"]?.partsOrQuestions
.length,
},
vehicle: {
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
style: vehicle.style,
vin: vehicle.vin ?? "",
},
};
let hasCalled = timeSlotCallFlags.shop;
if (!hasCalled) {
timeSlotCallFlags.shop = true;
}
const options = {
method: endpoints.GetShopTimeSlots.method,
endpoint: endpoints.GetShopTimeSlots.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
};
// Only set handler if this is the very first call in this session
if (!hasCalled) {
options.additionalSuccessEventDataHandler = (response) =>
getTimeSlotsAdditionalEventData(
response.data.provisionalTriggers,
order.serviceLocation.zipCode,
response.data.days?.[0]?.date,
shopAppointmentType
);
}
return globalMethods.callHttpClient(options);
},
getMobileTimeSlots(context, { payload: { startDate, endDate, zipCode }, pageNameToLog }) {
const order = context.state.order;
const vehicle = context.state.order.vehicle;
const payment = context.state.order.payment;
const lineItems = getFlattenedLineItemsWithGlassPartTag(order.lineItems);
const glassPieces = order.damage.glassToReplace
? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace)
: [];
var payload = {
startDate: startDate,
endDate: endDate,
applicationName: applicationConfig.APPLICATION_NAME,
parentAccountNumber: payment.parentAccountNumber,
carId: vehicle.carId,
lineItems: lineItems,
glassPieces: glassPieces,
eon: order.eon,
billToAccountNumber: context.getters.payment.billToAccountNumber,
coverage: {
status: payment.insuranceCoverage.coverageStatus,
deductible: order.policy.currentDeductible,
additionalAuthFlag: order.policy.additionalAuthFlag,
},
partSelection: {
hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length,
hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length,
hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length,
hasManuallySelectedParts:
!!context.state.applicationUser.pageData["vehicle-parts"]?.partsOrQuestions
.length,
},
vehicle: {
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
style: vehicle.style,
vin: vehicle.vin ?? "",
},
zipCode: zipCode ?? order.serviceLocation.zipCode,
};
let hasCalled = timeSlotCallFlags.mobile;
if (!hasCalled) {
timeSlotCallFlags.mobile = true;
}
const options = {
method: endpoints.GetMobileTimeSlots.method,
endpoint: endpoints.GetMobileTimeSlots.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
};
// Only set handler if this is the very first call in this session
if (!hasCalled) {
options.additionalSuccessEventDataHandler = (response) =>
getTimeSlotsAdditionalEventData(
response.data.provisionalTriggers,
order.serviceLocation.zipCode,
response.data.days?.[0]?.date
);
}
return globalMethods.callHttpClient(options);
},
getShopTimeSlotsV2(
context,
{ payload: { startDate, endDate, shopAppointmentType, providerNumbers }, pageNameToLog }
) {
const order = context.state.order;
const vehicle = context.state.order.vehicle;
const payment = context.state.order.payment;
const lineItems = getFlattenedLineItemsWithGlassPartTag(order.lineItems);
const glassPieces = order.damage.glassToReplace
? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace)
: [];
var payload = {
providerNumbers: providerNumbers,
startDate: startDate,
endDate: endDate,
shopAppointmentType: shopAppointmentType,
applicationName: applicationConfig.APPLICATION_NAME,
parentAccountNumber: payment.parentAccountNumber,
carId: vehicle.carId,
lineItems: lineItems,
glassPieces: glassPieces,
eon: order.eon,
billToAccountNumber: context.getters.payment.billToAccountNumber,
coverage: {
status: payment.insuranceCoverage.coverageStatus,
deductible: order.policy.currentDeductible,
additionalAuthFlag: order.policy.additionalAuthFlag,
},
partSelection: {
hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length,
hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length,
hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length,
hasManuallySelectedParts:
!!context.state.applicationUser.pageData["vehicle-parts"]?.partsOrQuestions
.length,
},
vehicle: {
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
style: vehicle.style,
vin: vehicle.vin ?? "",
},
};
let hasCalled = timeSlotCallFlags.shopV2;
if (!hasCalled) {
timeSlotCallFlags.shopV2 = true;
}
const options = {
method: endpoints.GetShopTimeSlotsV2.method,
endpoint: endpoints.GetShopTimeSlotsV2.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
};
// Only set handler if this is the very first call in this session
if (!hasCalled) {
options.additionalSuccessEventDataHandler = (response) => {
const firstProviderTimeSlots = response.data.providerTimeSlots?.[0];
return getTimeSlotsAdditionalEventData(
firstProviderTimeSlots?.provisionalTriggers,
order.serviceLocation.zipCode,
firstProviderTimeSlots?.days?.[0]?.date,
shopAppointmentType
);
};
}
return globalMethods.callHttpClient(options);
},
getMobileTimeSlotsV2(context, { payload: { startDate, endDate, zipCode }, pageNameToLog }) {
const order = context.state.order;
const vehicle = context.state.order.vehicle;
const payment = context.state.order.payment;
const lineItems = getFlattenedLineItemsWithGlassPartTag(order.lineItems);
const glassPieces = order.damage.glassToReplace
? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace)
: [];
var payload = {
startDate: startDate,
endDate: endDate,
applicationName: applicationConfig.APPLICATION_NAME,
parentAccountNumber: payment.parentAccountNumber,
carId: vehicle.carId,
lineItems: lineItems,
glassPieces: glassPieces,
eon: order.eon,
billToAccountNumber: context.getters.payment.billToAccountNumber,
coverage: {
status: payment.insuranceCoverage.coverageStatus,
deductible: order.policy.currentDeductible,
additionalAuthFlag: order.policy.additionalAuthFlag,
},
partSelection: {
hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length,
hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length,
hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length,
hasManuallySelectedParts:
!!context.state.applicationUser.pageData["vehicle-parts"]?.partsOrQuestions
.length,
},
vehicle: {
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
style: vehicle.style,
vin: vehicle.vin ?? "",
},
zipCode: zipCode ?? order.serviceLocation.zipCode,
};
let hasCalled = timeSlotCallFlags.mobileV2;
if (!hasCalled) {
timeSlotCallFlags.mobileV2 = true;
}
const options = {
method: endpoints.GetMobileTimeSlotsV2.method,
endpoint: endpoints.GetMobileTimeSlotsV2.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
};
// Only set handler if this is the very first call in this session
if (!hasCalled) {
options.additionalSuccessEventDataHandler = (response) =>
getTimeSlotsAdditionalEventData(
response.data.provisionalTriggers,
order.serviceLocation.zipCode,
response.data.days?.[0]?.date
);
}
return globalMethods.callHttpClient(options);
},
getMobilePremiumFee(context, { pageNameToLog }) {
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
const paymentType = context.getters.order.payment.isInsurance ? "Insurance" : "Cash";
return globalMethods.callHttpClient({
method: endpoints.GetMobilePremiumFee.method,
endpoint: `${endpoints.GetMobilePremiumFee.url}/${paymentType}/${damageType}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
// Signing Service for Payment
getSignature() {
return globalMethods.callHttpClient({
method: endpoints.GetSignature.method,
endpoint: endpoints.GetSignature.url,
});
},
// Session API Actions
saveQuote(context, { pageNameToLog, payload }) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
const order = context.state.order;
const applicationUser = context.getters.applicationUser;
const lineItems = context.state.order.lineItems;
const excludeRecalInquote = context.getters.shouldHideRecalibration;
return globalMethods.callHttpClient({
method: endpoints.SaveQuote.method,
endpoint: endpoints.SaveQuote.url,
payload: {
referralCorrelationId: order.referralCorrelationId,
referralNumber: order.referralNumber?.toString(),
referralSequenceNumber: order.referralSequenceNumber,
emailAddress: order.customer.emailAddress || undefined,
phoneNumber: order.customer.phoneNumber || undefined,
lastPage: pageNameToLog,
isRepair: damage.isRepair,
firstName: order.customer.firstName,
lastName: order.customer.lastName,
savedSessionId: applicationUser.savedSessionId,
serviceState: order.serviceLocation.state,
serviceZipCode: order.serviceLocation.zipCode,
parentAccountNumber: order.payment.parentAccountNumber,
excludeRecalInquote: excludeRecalInquote,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
subType: vehicle.vehicleSubType,
specialClass: vehicle.vehicleSpecialClass,
isBigTruck: vehicle.isBigTruck,
isInsurance: order.payment.isInsurance ?? false,
isVerified: order.payment.insuranceCoverage.isVerified ?? false,
lineItems: {
glassParts: lineItems.glassParts,
supportingItems: lineItems.supportingItems,
vaps: lineItems.vaps,
serverData: lineItems.serverData,
promos: lineItems.promos,
},
coverageStatus: order.payment.insuranceCoverage.coverageStatus ?? "",
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
saveSession(context, { pageNameToLog, payload }) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
const order = context.state.order;
const applicationUser = context.getters.applicationUser;
const lineItems = context.state.order.lineItems;
const submitAfterSave = payload?.submitAfterSave === "true";
const createUnscheduledStatusWorkOrderForPIA =
payload?.createUnscheduledStatusWorkOrderForPIA === "true";
// create a new array to avoid mutating state
const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace);
//affiliate cookie save only when submitAfterSave
const affiliateCookies = submitAfterSave ? applicationUser.affiliateCookies : null;
let endPoint = endpoints.SaveSession.url;
if (createUnscheduledStatusWorkOrderForPIA) {
endPoint = endpoints.SubmitOrderForPia.url;
}
if (submitAfterSave) {
endPoint = endpoints.SubmitOrder.url;
}
return globalMethods.callHttpClient({
method: endpoints.SaveSession.method,
endpoint: endPoint,
payload: {
submitAfterSave: submitAfterSave,
userAgent: navigator.userAgent,
applicationUser: {
crmCustomerId: applicationUser.crmCustomerId,
experiments: applicationUser.experiments,
lastPage: applicationUser.lastPageVisited,
pageData: applicationUser.pageData,
savedSessionId: applicationUser.savedSessionId,
affiliateCookies: affiliateCookies,
},
order: {
vehicle: {
carId: vehicle.carId,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
style: vehicle.style,
vin: vehicle.vin,
vehicleSubType: vehicle.vehicleSubType,
vehicleSpecialClass: vehicle.vehicleSpecialClass,
isBigTruck: vehicle.isBigTruck,
canSafeliteService: vehicle.canSafeliteService,
vinRequired: vehicle.vinRequired,
registration: {
firstName: vehicle.registration.firstName,
lastName: vehicle.registration.lastName,
streetAddress: vehicle.registration.address,
city: vehicle.registration.city,
state: vehicle.registration.state,
zipCode: vehicle.registration.zipCode,
licensePlateNumber: vehicle.registration.licensePlate,
},
},
customer: {
emailAddress: order.customer.emailAddress,
firstName: order.customer.firstName,
lastName: order.customer.lastName,
isSmsOptIn: order.customer.isSmsOptIn,
phoneNumber: order.customer.phoneNumber,
address: {
streetAddress: order.customer.address.streetAddress,
streetAddress2: order.customer.address.streetAddress2,
city: order.customer.address.city,
state: order.customer.address.state,
zipCode: order.customer.address.zipCode,
},
},
damage: {
numberOfChips: damage.numberOfChips,
glassToReplace: newGlassToReplace,
isRepair: damage.isRepair,
partQuestionAnswers: order.damage.partQuestionAnswers,
moldingQuestionAnswers: order.damage.moldingQuestionAnswers,
capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers,
installOemGlass: order.damage.installOemGlass,
dateOfLoss: order.damage.dateOfLoss,
damageCause: order.damage.damageCause,
},
lineItems: {
glassParts: lineItems.glassParts,
supportingItems: lineItems.supportingItems,
vaps: lineItems.vaps,
serverData: lineItems.serverData,
promos: lineItems.promos,
},
payment: {
InsuranceCoverage: {
isVerified: order.payment.insuranceCoverage.isVerified ?? false,
coverageStatus:
order.payment.insuranceCoverage.coverageStatus?.toString(),
coverageVerificationType:
order.payment.insuranceCoverage.coverageVerificationType,
coverageSubStatus: order.payment.insuranceCoverage.coverageSubStatus,
claimNumber: order.payment.insuranceCoverage.claimNumber,
},
isInsurance: order.payment.isInsurance,
parentAccountNumber: order.payment.parentAccountNumber,
billToAccountNumber: order.payment.billToAccountNumber,
isClaimAndCoverage: order.payment.isClaimAndCoverage,
canScheduleOnline: order.payment.canScheduleOnline,
isManagedAccount: order.payment.isManagedAccount,
inactivePromos: order.payment.inactivePromos,
isCreditCard:
order.payment.piaType == paymentMethods.CREDIT_CARD ? true : false,
isPaypal: order.payment.piaType == paymentMethods.PAYPAL ? true : false,
isAfterPay: order.payment.piaType == paymentMethods.AFTERPAY ? true : false,
isApplePay:
order.payment.piaType == paymentMethods.APPLE_PAY ? true : false,
paypalToken: order.payment.paypalToken,
nextGenSettledAmount: order.payment.nextGenSettledAmount,
ccToken: {
subscriptionId: order.payment.ccToken.subscriptionId,
expMonth: order.payment.ccToken.expMonth,
expYear: order.payment.ccToken.expYear,
cardType: order.payment.ccToken.cardType,
billToPostalCode: order.payment.ccToken.billToPostalCode,
billToFirstName: order.payment.ccToken.billToFirstName,
billToLastName: order.payment.ccToken.billToLastName,
referenceNumber: order.payment.ccToken.referenceNumber,
authCode: order.payment.ccToken.authCode,
transactionId: order.payment.ccToken.transactionId,
transReferenceNumber: order.payment.ccToken.transReferenceNumber,
lastFour: order.payment.ccToken.lastFour,
},
},
policy: {
isItac: order.policy?.isItac,
isNoComp: order.policy?.isNoComp,
currentDeductible: order.policy?.currentDeductible,
originalDeductible: order.policy?.originalDeductible,
policyNumber: order.policy?.policyNumber,
},
serviceLocation: {
streetAddress: order.serviceLocation.address,
streetAddress2: order.serviceLocation.address2,
city: order.serviceLocation.city,
state: order.serviceLocation.state,
zipCode: order.serviceLocation.zipCode,
zipCodeCtu: order.serviceLocation.zipCodeCtu,
appointmentType: order.serviceLocation.appointmentType,
isVehicleProtected: order.serviceLocation.isVehicleProtected,
provider: {
providerNumber: order.serviceLocation.provider?.providerNumber,
address: {
streetAddress:
order.serviceLocation.provider?.address?.streetAddress,
city: order.serviceLocation.provider?.address?.city,
state: order.serviceLocation.provider?.address?.state,
zipCode: order.serviceLocation.provider?.address?.zipCode,
zipCodeCtu: order.serviceLocation.provider?.address?.zipCodeCtu,
},
},
techNotes: order.serviceLocation.techNotes,
},
schedule: {
date: order.schedule?.date,
startTime: order.schedule?.startTime,
endTime: order.schedule?.endTime,
routeCode: order.schedule?.routeCode,
jobMaxMinutes: order.schedule?.jobMaxMinutes,
jobMinMinutes: order.schedule?.jobMinMinutes,
},
referralCorrelationId: order.referralCorrelationId,
referralDate: order.referralDate,
referralNumber: order.referralNumber?.toString(),
referralSequenceNumber: order.referralSequenceNumber,
eon: order.eon,
createUnscheduledStatusWorkOrderForPIA: createUnscheduledStatusWorkOrderForPIA,
lockToken: order.lockToken,
isRecalAckOptIn: order.isRecalAckOptIn,
isMSRFeeApplicable: order.isMSRFeeApplicable,
isMSRFeeCoveredByInsurance: order.isMSRFeeCoveredByInsurance,
cashPriceSubTotal: order.cashPriceSubTotal,
},
},
logApiCall: true,
pageNameToLog: pageNameToLog,
additionalSuccessEventDataHandler: (response) =>
"Email provided: " + (order.customer.emailAddress ? "true" : "false"),
});
},
loadSession(
context,
{
payload: {
savedSessionId,
referralNumber,
referralDate,
parentAccountNumber,
referralCorrelationId,
isConceptInsurance,
},
pageNameToLog,
}
) {
const order = context.state.order;
var dtParts = referralDate.split("-");
const year = dtParts[0];
const month = dtParts[1];
const day = dtParts[2].substring(0, 2);
const loadDate = `${year}-${month}-${day}`;
return globalMethods
.callHttpClient({
method: endpoints.LoadSession.method,
endpoint: endpoints.LoadSession.url,
payload: {
savedSessionId: savedSessionId?.toString(),
referralNumber: referralNumber?.toString(),
referralDate: loadDate,
parentAccountNumber: parentAccountNumber?.toString(),
referralCorrelationId: referralCorrelationId,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
})
.then(
async (response) => {
// Flatten location and name properties
response.data.order.damage?.glassToReplace?.map((glass) => {
glass.glassLocation = glass.location;
glass.glassName = glass.name;
delete glass.location;
delete glass.name;
return glass;
});
// clear the state if the existing EON does not equal what is returned from loadSession
if (
context.state.order.eon &&
context.state.order.eon != response.data.order.eon
) {
context.commit(storeMutations.RESET_STATE);
}
context.commit(
storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION,
response.data
);
await resetScheduleIfUnavailable(context, context.state.order, pageNameToLog);
return response;
},
(error) => {
deleteFunnelCookie();
context.commit(storeMutations.RESET_STATE);
}
);
},
saveCCToken(context, ccToken) {
context.commit(storeMutations.UPDATE_CCTOKEN, ccToken);
},
saveNextGenSettledAmount(context, nextGenSettledAmount) {
context.commit(storeMutations.UPDATE_NEXTGEN_SETTLED_AMOUNT, nextGenSettledAmount);
},
savePaypalToken(context, ppToken) {
context.commit(storeMutations.UPDATE_PAYPAL_TOKEN, ppToken);
},
// Business domain actions
// Vehicle
saveVehicle(
context,
{
year,
make,
model,
style,
vehicleSubType,
vehicleSpecialClass,
isBigTruck,
carId,
category,
canSafeliteService,
imageUrl,
imageVifNumber,
imageVifColor,
skipVINLookup,
skipPartQuestions,
vinRequired,
}
) {
if (
context.state.order.vehicle.year != year ||
context.state.order.vehicle.make != make ||
context.state.order.vehicle.model != model ||
context.state.order.vehicle.style != style
) {
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
context.commit(storeMutations.UPDATE_YEAR, year);
context.commit(storeMutations.UPDATE_MAKE, make);
context.commit(storeMutations.UPDATE_MODEL, model);
context.commit(storeMutations.UPDATE_STYLE, style);
context.commit(storeMutations.UPDATE_VEHICLE_SUBTYPE, vehicleSubType);
context.commit(storeMutations.UPDATE_VEHICLE_SPECIAL_CLASS, vehicleSpecialClass);
context.commit(storeMutations.UPDATE_IS_BIGTRUCK, isBigTruck);
context.commit(storeMutations.UPDATE_CAR_ID, carId);
context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, category);
context.commit(storeMutations.UPDATE_VEHICLE_CAN_SAFELITE_SERVICE, canSafeliteService);
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_SKIP_VIN_LOOKUP, skipVINLookup);
context.commit(storeMutations.UPDATE_SKIP_PART_QUESTIONS, skipPartQuestions);
context.commit(storeMutations.UPDATE_VIN_REQUIRED, vinRequired);
}
},
saveVehicleDamage(
context,
{ isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }
) {
const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort();
const isGlassToReplaceTheSame =
context.state.order.damage.glassToReplace?.length === selectedGlassToReplace.length &&
context.state.order.damage.glassToReplace
.slice()
.sort()
.every(
(obj, index) =>
obj.glassLocation === selectedGlassPassedInSorted[index].glassLocation &&
obj.glassName === selectedGlassPassedInSorted[index].glassName
);
const isWindshieldRepairTheSame =
isWindshieldRepair === context.state.order.damage.isRepair;
const isChipCountTheSame =
selectedWindshieldChipCount === context.state.order.damage.numberOfChips;
const isDamageChanging =
!isGlassToReplaceTheSame ||
!isWindshieldRepairTheSame ||
(isWindshieldRepair && !isChipCountTheSame);
if (isDamageChanging) {
//Reset dependent state when changing
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
// Save new values
context.commit(storeMutations.UPDATE_IS_REPAIR, isWindshieldRepair);
context.commit(
storeMutations.UPDATE_NUMBER_OF_CHIPS,
isWindshieldRepair ? parseInt(selectedWindshieldChipCount) : null
);
context.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, selectedGlassToReplace);
}
},
// Vin lookup
saveVinLookup(context, { isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) {
//Reset dependent state when changing
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
if (!isSelectedGlassAvailableForVehicle) {
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
}
//Save new values
context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo);
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
}
},
saveRegistrationLicensePlateLookup(
context,
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
) {
//Reset dependent state when changing
if (
registrationInfo?.licensePlate !==
context.state.order.vehicle.registration?.licensePlate
) {
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
if (!isSelectedGlassAvailableForVehicle) {
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
}
context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo);
if (registrationInfo) {
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
// only update name information if there isn't a value in state already
if (!context.getters.order.customer.firstName) {
context.commit(storeMutations.UPDATE_CUSTOMER_DETAILS, {
firstName: registrationInfo.firstName,
lastName: registrationInfo.lastName,
});
}
}
}
},
saveRegistrationAddressLookup(
context,
{ isSelectedGlassAvailableForVehicle, vehicleInfo, customerInfo }
) {
//Reset dependent state when changing
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
if (!isSelectedGlassAvailableForVehicle) {
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
}
}
context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo);
// only update name information if there isn't a value in state already
if (!context.getters.order.customer.firstName && customerInfo) {
context.commit(storeMutations.UPDATE_CUSTOMER_DETAILS, {
firstName: customerInfo.firstName,
lastName: customerInfo.lastName,
});
}
},
savePartQuestionAnswers(context, partQuestionAnswersArray) {
// if part question answers have changed, reset subsequent question answers
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
context.getters.damage.partQuestionAnswers,
"result"
);
const sortedPartQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(
partQuestionAnswersArray,
"result"
);
const havePartQuestionAnswersChanged =
sortedPreviousResultsArray?.length !== sortedPartQuestionAnswersArray.length ||
!sortedPreviousResultsArray?.every(
(x, i) => x.result === sortedPartQuestionAnswersArray[i].result
);
if (havePartQuestionAnswersChanged) {
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
context.commit(storeMutations.UPDATE_PAGE_DATA, {
page: routeData.VEHICLE_PARTS.name,
data: null,
});
context.commit(storeMutations.UPDATE_PAGE_DATA, {
page: routeData.MOLDING_QUESTIONS.name,
data: null,
});
context.commit(storeMutations.UPDATE_PAGE_DATA, {
page: routeData.CAPABILITY_QUESTIONS.name,
data: null,
});
}
//Save new values
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
},
resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) {
const partsOrQuestionsDataToCompareWith =
context.getters.pageData(routeData.MOLDING_QUESTIONS.name)?.partsOrQuestions ??
context.getters.pageData(routeData.CAPABILITY_QUESTIONS.name)?.partsOrQuestions ??
[];
function getAllPartNumbers(partsOrQuestions) {
return partsOrQuestions[0]?.parts
? [...partsOrQuestions]
.map((glass) => glass.parts)
.flat()
.map((part) => part.partNumber)
.filter((partNumber) => !partNumber.toUpperCase().includes("FEE"))
.sort()
.join(",")
: [];
}
const previouslySelectedPartNumbers = getAllPartNumbers(partsOrQuestionsDataToCompareWith);
const currentlySelectedPartNumbers = getAllPartNumbers(matchedParts);
const haveSelectedVehiclePartsChanged =
previouslySelectedPartNumbers !== currentlySelectedPartNumbers;
if (haveSelectedVehiclePartsChanged) {
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
context.commit(storeMutations.UPDATE_PAGE_DATA, {
page: routeData.MOLDING_QUESTIONS.name,
data: null,
});
context.commit(storeMutations.UPDATE_PAGE_DATA, {
page: routeData.CAPABILITY_QUESTIONS.name,
data: null,
});
}
},
saveMoldingQuestionAnswers(context, moldingQuestionAnswers) {
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
context.getters.damage.moldingQuestionAnswers,
"partNum"
);
const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(
moldingQuestionAnswers,
"partNum"
);
const haveMoldingQuestionAnswersChanged =
sortedPreviousResultsArray?.length !== sortedMoldingQuestionAnswersArray.length ||
!sortedPreviousResultsArray?.every(
(x, i) => x.partNum === sortedMoldingQuestionAnswersArray[i].partNum
);
if (haveMoldingQuestionAnswersChanged) {
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
context.commit(storeMutations.UPDATE_PAGE_DATA, {
page: routeData.CAPABILITY_QUESTIONS.name,
data: null,
});
}
//Save new values
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers);
},
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
context.getters.damage.capabilityQuestionAnswers,
"result"
);
const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(
capabilityQuestionAnswers,
"result"
);
const haveCapabilityQuestionAnswersChanged =
sortedPreviousResultsArray?.length !== sortedCapabilityQuestionAnswersArray.length ||
!sortedPreviousResultsArray?.every(
(x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result
);
if (haveCapabilityQuestionAnswersChanged) {
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
}
//Save new values
context.commit(
storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS,
capabilityQuestionAnswers
);
},
savePaymentType(context, isInsurance) {
if (isInsurance !== context.getters.payment.isInsurance) {
context.commit(storeMutations.RESET_PAYMENT_METHOD_CHOICE);
}
context.commit(storeMutations.UPDATE_IS_INSURANCE, isInsurance);
},
savePaymentMethodChoice(context, paymentMethod) {
var isPia = null;
if (paymentMethod !== paymentMethods.NONE) {
isPia = paymentMethod !== paymentMethods.LATER;
}
context.commit(storeMutations.UPDATE_IS_PIA, isPia);
context.commit(storeMutations.UPDATE_PIA_TYPE, isPia ? paymentMethod : null);
},
saveIsRecalAckOptIn(context, isRecalAckOptIn) {
context.commit(storeMutations.UPDATE_IS_RECAL_ACK_OPT_IN, isRecalAckOptIn);
},
saveIsRecalAcknowledgedForScheduling(context, isRecalAcknowledgedForScheduling) {
context.commit(
storeMutations.UPDATE_IS_RECAL_ACKNOWLEDGED_FOR_SCHEDULING,
isRecalAcknowledgedForScheduling
);
},
saveIsOemGlassSelected(context, isOemGlassSelected) {
context.commit(storeMutations.UPDATE_IS_OEM_GLASS_SELECTED, isOemGlassSelected);
},
saveIsMSRFeeApplicable(context, isMSRFeeApplicable) {
context.commit(storeMutations.UPDATE_IS_MSR_FEE_APPLICABLE, isMSRFeeApplicable);
},
saveIsMSRFeeCoveredByInsurance(context, isMSRFeeCoveredByInsurance) {
context.commit(
storeMutations.UPDATE_IS_MSR_FEE_COVERED_BY_INSURANCE,
isMSRFeeCoveredByInsurance
);
},
saveIsNewInsuranceFlow(context, isNewInsuranceFlow) {
context.commit(storeMutations.UPDATE_IS_NEW_INSURANCE_FLOW, isNewInsuranceFlow);
},
saveParentAccountNumber(context, parentAccountNumber) {
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber);
},
saveAccountName(context, accountName) {
context.commit(storeMutations.UPDATE_ACCOUNT_NAME, accountName);
},
saveInsuranceAccountDetails(
context,
{ isClaimAndCoverage, canScheduleOnline, isManagedAccount }
) {
context.commit(storeMutations.UPDATE_IS_CLAIM_AND_COVERAGE, isClaimAndCoverage);
context.commit(storeMutations.UPDATE_CAN_SCHEDULE_ONLINE, canScheduleOnline);
context.commit(storeMutations.UPDATE_IS_MANAGED_ACCOUNT, isManagedAccount);
},
saveBillToAccountNumber(context, billToAccountNumber) {
context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber);
},
resetInsuranceDetails(context) {
context.commit(storeMutations.RESET_INSURANCE_DETAILS);
},
saveSupportingItems(context, supportingItems) {
syncLineItemIds(supportingItems, context.state.order.lineItems.supportingItems);
if (!supportingItemsEqual(supportingItems, context.state.order.lineItems.supportingItems)) {
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
}
addGuidToLineItemsIfNotAlreadyThere(supportingItems);
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems);
},
saveSupportingItemsSuppressingStateResetting(context, supportingItems) {
addGuidToLineItemsIfNotAlreadyThere(supportingItems);
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems);
},
saveVaps(context, vaps) {
addGuidToLineItemsIfNotAlreadyThere(vaps);
context.commit(storeMutations.UPDATE_VAPS, vaps);
},
// Manage promo saving to ensure a promoCode never ends up in both active and inactive
saveActiveAndOrInactivePromos(context, { activePromos = null, inactivePromos = null }) {
if (inactivePromos) {
// Clean up inactivePromos
// Remove bundle identifier
inactivePromos = inactivePromos.map((promoCode) =>
getPromoCodeWithoutBundleIdentifier(promoCode)
);
// Remove duplicates
inactivePromos = inactivePromos.filter(
(promoCode, index) => inactivePromos.indexOf(promoCode) === index
);
}
activePromos = activePromos?.slice(0);
inactivePromos = inactivePromos?.slice(0);
let activePromosToSave;
let inactivePromosToSave;
if (!activePromos && !inactivePromos) {
// Allow double null to save empty arrays to store
activePromosToSave = [];
inactivePromosToSave = [];
} else if (activePromos && inactivePromos) {
// Prioritize active promos when both inactive and active are supplied
activePromosToSave = activePromos;
inactivePromosToSave = removeCurrentlyActivePromoCodesFromInactivePromos(
activePromosToSave,
inactivePromos
);
} else if (!activePromos) {
// Only inactivePromos supplied
inactivePromosToSave = inactivePromos;
activePromosToSave = (context.getters.lineItems.promos ?? []).filter((activePromo) => {
return !inactivePromosToSave.includes(
getPromoCodeWithoutBundleIdentifier(activePromo.promoCode)
);
});
} else if (!inactivePromos) {
// Only activePromos supplied
activePromosToSave = activePromos;
inactivePromosToSave = removeCurrentlyActivePromoCodesFromInactivePromos(
activePromosToSave,
context.getters.payment.inactivePromos ?? []
);
}
context.commit(storeMutations.UPDATE_PROMOS, activePromosToSave);
context.commit(storeMutations.UPDATE_INACTIVE_PROMOS, inactivePromosToSave);
},
// Price order actions
async priceOrderItemsAndSaveServerData(
context,
{ payload: { availableLineItems, serviceZipCode, serviceZipCodeCtu }, pageNameToLog }
) {
const flattenedLineItemsWithChildParts =
getFlattenedArrayOfLineItemsWithChildParts(availableLineItems);
const lineItemsWithOnlyPartNumbers = flattenedLineItemsWithChildParts.map((lineItem) => ({
partNumber: lineItem.partNumber,
}));
const order = context.getters.order;
var providerNumber =
order.serviceLocation?.provider?.providerNumber ?? order.serviceLocation?.zipCodeCtu;
if (providerNumber.startsWith("00") && providerNumber.length > 5) {
providerNumber = providerNumber.substring(1);
}
const response = await globalMethods.callHttpClient({
method: endpoints.PriceOrderItems.method,
endpoint: endpoints.PriceOrderItems.url,
payload: {
parentAccountNumber: order.payment?.parentAccountNumber,
billToAccountNumber:
order.payment?.billToAccountNumber ??
applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER,
providerNumber: providerNumber,
carId: order.vehicle.carId,
year: order.vehicle.year,
make: order.vehicle.make,
model: order.vehicle.model,
eon: order.eon,
state: order.serviceLocation?.state,
referralNumber: order.referralNumber,
referralSequenceNumber: order.referralSequenceNumber,
zipCode: order.serviceLocation?.zipCode,
serviceZipCode: serviceZipCode ?? order.serviceLocation?.zipCode,
referralDate: order.referralDate,
isReplacement: !order.damage.isRepair,
deductible: order.policy?.currentDeductible,
coverageStatus: order.payment?.insuranceCoverage?.coverageStatus,
lineItems: lineItemsWithOnlyPartNumbers,
serverData: order.lineItems.serverData ? order.lineItems.serverData : "",
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData);
availableLineItems = addPricesToLineItems(availableLineItems, response.data.lineItems);
return availableLineItems;
},
// Tax order actions
async taxOrderItemsAndSaveServerData(
context,
{
payload: {
billToAccountNumber,
providerNumber,
appointmentType,
serviceLocationCity,
serviceLocationState,
serviceLocationZipCode,
pricedLineItems,
serviceLocationAddressLine1,
serviceLocationAddressLine2,
},
pageNameToLog,
}
) {
const arrayOfLineItems = [
...(pricedLineItems.glassParts ?? []),
...(pricedLineItems.promos ?? []),
...(pricedLineItems.supportingItems ?? []),
...(pricedLineItems.vaps ?? []),
];
const flattenedLineItemsWithChildParts =
getFlattenedArrayOfLineItemsWithChildParts(arrayOfLineItems);
const lineItemsWithOnlyPriceInfo = flattenedLineItemsWithChildParts.map((lineItem) => ({
partNumber: lineItem.partNumber,
laborAmount: lineItem.laborAmount ?? 0,
kitPrice: lineItem.kitPrice ?? 0,
sellingPrice: lineItem.sellingPrice ?? 0,
promoCode: lineItem.promoCode ?? null,
}));
const order = context.getters.order;
const response = await globalMethods.callHttpClient({
method: endpoints.TaxOrderItems.method,
endpoint: endpoints.TaxOrderItems.url,
payload: {
parentAccountNumber: order.payment.parentAccountNumber,
billToAccountNumber: billToAccountNumber,
providerNumber: providerNumber,
appointmentType: appointmentType,
pricedLineItems: lineItemsWithOnlyPriceInfo,
serviceLocation: {
addressLine1: appointmentType == "Mobile" ? serviceLocationAddressLine1 : null,
addressLine2: appointmentType == "Mobile" ? serviceLocationAddressLine2 : null,
city: appointmentType == "Mobile" ? serviceLocationCity : null,
state: appointmentType == "Mobile" ? serviceLocationState : null,
zipCode: appointmentType == "Mobile" ? serviceLocationZipCode : null,
},
serverData: order.lineItems.serverData ? order.lineItems.serverData : "",
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData);
Object.keys(pricedLineItems).forEach((key) => {
pricedLineItems[key] = addTaxesToPricedLineItems(
pricedLineItems[key] ?? [],
response.data.taxedLineItems
);
});
return pricedLineItems;
},
// The <addableVaps> parameter is an array of ALL available front wipers and Rain Repel
// for the vehicle. There is no need to confirm an addableVap is not already on the order
// <lineItemsToUse> is an optional parameter if the lineItems in the store may not be up to date
async validateOrderPromoAndSaveServerData(
context,
{
payload: {
promoCode,
lineItemsToUse,
addableVaps,
useDefaultCashParentAccount = false,
},
pageNameToLog,
}
) {
const order = context.getters.order;
lineItemsToUse = lineItemsToUse ?? order.lineItems;
addGuidToLineItemsIfNotAlreadyThere(lineItemsToUse.vaps);
syncLineItemIds(addableVaps, lineItemsToUse.vaps);
// addableVaps still won't have IDs if they weren't already in lineItemsToUse
addGuidToLineItemsIfNotAlreadyThere(addableVaps);
const requestObject = {
promoCode: promoCode,
addableVaps: addableVaps,
order: {
appointmentType: order.serviceLocation.appointmentType,
carId: order.vehicle.carId,
correlationId: order.referralCorrelationId,
eon: order.eon,
isInsurance: order.payment.isInsurance,
isRepair: order.damage.isRepair,
glassToReplace: renameGlassToReplaceAttributes(order.damage.glassToReplace),
lineItemsOnOrder: getArrayOfAllLineItemsAndChildParts(lineItemsToUse),
parentAccountNumber: useDefaultCashParentAccount
? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER
: order.payment.parentAccountNumber,
referralSequenceNumber: order.referralSequenceNumber,
serviceState: order.serviceLocation.state,
serverData: order.lineItems.serverData,
vehicleYear: "" + order.vehicle.year,
zipCodeOrProviderCtu:
order.serviceLocation.appointmentType === "Inshop"
? order.serviceLocation.provider.address.zipCodeCtu
: order.serviceLocation.zipCodeCtu,
},
};
const validateResponse = await globalMethods
.callHttpClient({
method: endpoints.ValidatePromo.method,
endpoint: endpoints.ValidatePromo.url,
payload: requestObject,
logApiCall: true,
pageNameToLog: pageNameToLog,
})
.catch((error) => {
// Validate promo will return 4xx errors when an invalid promo
return error;
});
if (validateResponse?.data?.serverData) {
context.commit(
storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA,
validateResponse.data.serverData
);
}
return validateResponse?.data;
},
// All payload parameters are optional - will use store data if not provided
async revalidateOrderPromosAndSaveServerData(
context,
{
payload: {
activePromosToUse,
inactivePromosToUse,
lineItemsToUse,
useDefaultCashParentAccount = false,
},
pageNameToLog,
}
) {
const order = context.getters.order;
activePromosToUse = activePromosToUse ?? order.lineItems.promos;
lineItemsToUse = lineItemsToUse ? deepClone(lineItemsToUse) : deepClone(order.lineItems);
addGuidToLineItemsIfNotAlreadyThere(lineItemsToUse.vaps);
lineItemsToUse.promos = activePromosToUse;
inactivePromosToUse = inactivePromosToUse ?? order.payment.inactivePromos;
inactivePromosToUse = removeCurrentlyActivePromoCodesFromInactivePromos(
lineItemsToUse.promos,
inactivePromosToUse
);
let requestObject = {
inactivePromos: inactivePromosToUse,
order: {
appointmentType: order.serviceLocation.appointmentType,
carId: order.vehicle.carId,
correlationId: order.referralCorrelationId,
eon: order.eon,
isInsurance: order.payment.isInsurance,
isRepair: order.damage.isRepair,
glassToReplace: renameGlassToReplaceAttributes(order.damage.glassToReplace),
lineItemsOnOrder: getArrayOfAllLineItemsAndChildParts(lineItemsToUse),
parentAccountNumber: useDefaultCashParentAccount
? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER
: order.payment.parentAccountNumber,
referralSequenceNumber: order.referralSequenceNumber,
serviceState: order.serviceLocation.state,
serverData: order.lineItems.serverData,
vehicleYear: "" + order.vehicle.year,
zipCodeOrProviderCtu:
order.serviceLocation.appointmentType === "Inshop"
? order.serviceLocation.provider.address.zipCodeCtu
: order.serviceLocation.zipCodeCtu,
},
};
const revalidateResponse = await globalMethods.callHttpClient({
method: endpoints.RevalidatePromos.method,
endpoint: endpoints.RevalidatePromos.url,
payload: requestObject,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
context.commit(
storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA,
revalidateResponse.data.lineItemsServerData
);
return revalidateResponse?.data;
},
///////////////////////////
// Account Service Calls //
///////////////////////////
// List all insurance companies
async getInsuranceCompanyList(context, { pageNameToLog }) {
const insuranceCompanyList = await globalMethods.callHttpClient({
method: endpoints.GetInsuranceCompanyList.method,
endpoint: endpoints.GetInsuranceCompanyList.url,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
return insuranceCompanyList.data.sort((a, b) => {
const nameA = a.accountName.toUpperCase();
const nameB = b.accountName.toUpperCase();
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
});
},
// Get BillToAccountNumber
async getBillToAccountNumber(
context,
{
payload: {
parentAccountNumber = context.getters.order.payment.parentAccountNumber,
providerNumber = context.getters.order.serviceLocation.zipCodeCtu,
isItac = context.getters.order.policy.isItac,
},
pageNameToLog,
}
) {
if (!parentAccountNumber) {
parentAccountNumber = applicationConfig.CASH_PARENT_ACCOUNT_NUMBER;
}
const queryString =
`ParentAccountNumber=${parentAccountNumber}` +
`&ProviderNumber=${providerNumber}` +
`&IsItac=${isItac}`;
const billToAccountNumberResponse = await globalMethods.callHttpClient({
method: endpoints.GetBillToAccountNumber.method,
endpoint: `${endpoints.GetBillToAccountNumber.url}?${queryString}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
return billToAccountNumberResponse.data.toString();
},
// Get Account Details
async getAccountDetails(context, { payload: { parentAccountNumber }, pageNameToLog }) {
const accountDetailsResponse = await globalMethods.callHttpClient({
method: endpoints.GetAccountDetails.method,
endpoint: `${endpoints.GetAccountDetails.url}/${parentAccountNumber}`,
});
return accountDetailsResponse.data;
},
//////////////////////////////////
// END OF Account Service Calls //
//////////////////////////////////
// Misc order actions
saveSchedule(context, scheduleInfo) {
context.commit(storeMutations.UPDATE_SCHEDULE, scheduleInfo);
},
saveCustomerDetails(context, customerDetails) {
context.commit(storeMutations.UPDATE_CUSTOMER_DETAILS, customerDetails);
},
saveInsuranceDetails(context, insuranceDetails) {
context.commit(storeMutations.UPDATE_INSURANCE_DETAILS, insuranceDetails);
},
saveDamageDetails(context, damageDetails) {
context.commit(storeMutations.UPDATE_DAMAGE_DETAILS, damageDetails);
},
saveServiceZipCodeInfo(context, serviceZipCodeInfo) {
if (
context.state.order.serviceLocation &&
serviceZipCodeInfo.zipCode !== context.state.order.serviceLocation.zipCode
) {
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
context.commit(storeMutations.RESET_SERVICE_LOCATION_MOBILE_ADDRESS);
}
context.commit(storeMutations.UPDATE_SERVICE_ZIP, serviceZipCodeInfo);
},
saveServiceLocation(context, serviceLocationInfo) {
if (context.state.order.serviceLocation) {
if (
serviceLocationInfo.zipCode !== context.state.order.serviceLocation.zipCode ||
!providersEqual(
serviceLocationInfo.provider,
context.state.order.serviceLocation.provider
) ||
serviceLocationInfo.appointmentType !==
context.state.order.serviceLocation.appointmentType
) {
context.commit(storeMutations.RESET_SCHEDULE);
context.commit(storeMutations.RESET_PAYMENT_METHOD_CHOICE);
}
}
context.commit(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocationInfo);
},
saveMobileDetails(context, mobileDetails) {
context.commit(storeMutations.UPDATE_MOBILE_DETAILS, mobileDetails);
},
saveServiceLocationTechNotes(context, techNotesInfo) {
context.commit(storeMutations.UPDATE_SERVICE_LOCATION_TECH_NOTES, techNotesInfo);
},
saveEmail(context, email) {
context.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, email === "" ? null : email);
},
savePhoneNumber(context, phoneNumber) {
context.commit(
storeMutations.UPDATE_CUSTOMER_PHONE_NUMBER,
phoneNumber === "" ? null : phoneNumber
);
},
saveIsSmsOptIn(context, isSmsOptIn) {
context.commit(storeMutations.UPDATE_CUSTOMER_IS_SMS_OPT_IN, isSmsOptIn);
},
saveWaitListRequested(context, waitListRequested) {
context.commit(storeMutations.UPDATE_CUSTOMER_WAITLIST_REQUESTED, waitListRequested);
},
savePageData(context, pageData) {
context.commit(storeMutations.UPDATE_PAGE_DATA, pageData);
},
saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) {
//Reset dependent state when changing
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
if (!isSelectedGlassAvailableForVehicle) {
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
}
//Save new values
context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo);
}
},
saveGlassParts(context, parts) {
if (!deepEqual(parts, context.state.order.lineItems.glassParts)) {
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
}
addGuidToLineItemsIfNotAlreadyThere(parts);
context.commit(storeMutations.UPDATE_GLASS_PARTS, parts);
},
saveGlassPartsSuppressingStateResetting(context, parts) {
context.commit(storeMutations.UPDATE_GLASS_PARTS, parts);
},
clearVin(context) {
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
},
isVinOptionalVehicle(context) {
if (context.state.order.vehicle.skipVINLookup) return true;
return false;
},
createSubmittedState(context) {
if (window.sessionStorage.getItem(sessionStorageKeyConstants.SUBMITTED_STATE) !== null) {
return;
}
// create a submitted order object from vuex.
const submittedState = {
order: context.state.order,
applicationUser: context.state.applicationUser,
};
const experiments = context.state.applicationUser.experiments;
const affiliateCookies = context.state.applicationUser.affiliateCookies;
// set to local storage
window.sessionStorage.setItem(
sessionStorageKeyConstants.SUBMITTED_STATE,
JSON.stringify(submittedState)
);
window.sessionStorage.setItem("createNewSessionForHeritage", true);
// clear vuex
context.commit(storeMutations.RESET_STATE);
// delete cookie
deleteFunnelCookie();
//restore user's experiments
context.commit(storeMutations.UPDATE_EXPERIMENTS, experiments);
//clear externalParameter session storage
window.sessionStorage.removeItem(sessionStorageKeyConstants.EXTERNAL_PARAMETER_STATE);
//restore affiliate cookies
context.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies);
context.commit(storeMutations.INCREMENT_SUBMITTED_STATE_REVISION);
},
addDonationToSubmittedState(context, donationAmount) {
const submittedOrder = deepClone(baseMixin.methods.getSubmittedOrder());
const submittedApplicationUser = deepClone(baseMixin.methods.getSubmittedApplicationUser());
submittedOrder.lineItems.supportingItems.push({
partNumber: `DONATION_${donationAmount}`,
description: `DONATION $${donationAmount}`,
partType: partTypeStrings.DONATION,
isInsurable: false,
isChildPart: false,
laborAmount: 0,
sellingPrice: donationAmount,
kitPrice: 0,
salesTax: 0,
});
addGuidToLineItemsIfNotAlreadyThere(submittedOrder.lineItems.supportingItems);
const submittedState = {
order: submittedOrder,
applicationUser: submittedApplicationUser,
};
// set to local storage
window.sessionStorage.setItem(
sessionStorageKeyConstants.SUBMITTED_STATE,
JSON.stringify(submittedState)
);
context.commit(storeMutations.INCREMENT_SUBMITTED_STATE_REVISION);
},
resetSubmittedState(context) {
// clear from local storage
window.sessionStorage.removeItem(sessionStorageKeyConstants.SUBMITTED_STATE);
context.commit(storeMutations.INCREMENT_SUBMITTED_STATE_REVISION);
},
resetExternalParameterState(context) {
if (context.getters.isExternalParameter) {
context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_VEHICLE_STATE);
context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_DAMAGE_STATE);
context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_ESTIMATE_STATE);
context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_SERVICEZIP_STATE);
context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_QUOTE_STATE);
context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_CUSTOMER_STATE);
context.commit(storeMutations.RESET_IS_EXTERNAL_PARAMETER);
}
},
updateExternalParameterMMS(context, externalParameterMMS) {
context.commit(
storeMutations.UPDATE_EXTERNAL_PARAMETER_MAKE,
externalParameterMMS.externalParameterMake
);
context.commit(
storeMutations.UPDATE_EXTERNAL_PARAMETER_MODEL,
externalParameterMMS.externalParameterModel
);
context.commit(
storeMutations.UPDATE_EXTERNAL_PARAMETER_STYLE,
externalParameterMMS.externalParameterStyle
);
},
saveLoggingOption(context, loggingOption) {
var option = false;
if (loggingOption != null) {
option = loggingOption == "true" ? true : false;
}
context.commit(storeMutations.UPDATE_LOGGING_OPTION, option);
},
async getRecalPartsAndSaveToLineItems(context, { pageNameToLog }) {
// identify each part that needs recal
const glassParts = context.state.order?.lineItems?.glassParts
? deepClone(context.state.order.lineItems.glassParts)
: [];
for (let i = 0; i < glassParts.length; i++) {
// does this part need recal?
const needsRecal =
!!glassParts[i].requiresRecalibration && !!glassParts[i].recalibrationType;
if (needsRecal) {
const recalType = glassParts[i].recalibrationType;
const parentAccountNumber =
context.state.order.payment.parentAccountNumber ??
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER;
// Get part from API
const urlExtension = `${context.state.order.vehicle.carId}/${glassParts[i].partNumber}/${recalType}/${parentAccountNumber}/${context.state.order.serviceLocation.zipCode}/${applicationConfig.ANALYTICS_APPLICATION_NAME}/${context.state.order.referralSequenceNumber}`;
const recalPartResponse = await globalMethods.callHttpClient({
method: endpoints.GetRecalPart.method,
endpoint: `${endpoints.GetRecalPart.url}/${urlExtension}`,
payload: {},
pageNameToLog: pageNameToLog,
});
// If any parts retrieved, add as children to the glass part.
if (
recalPartResponse.status === 200 &&
recalPartResponse.data.recalibrationParts?.length > 0
) {
if (!glassParts[i].childParts) {
glassParts[i].childParts = [];
}
glassParts[i].childParts.push(...recalPartResponse.data.recalibrationParts);
context.dispatch(storeActions.SAVE_GLASS_PARTS, glassParts);
}
}
}
},
updateHasTriggeredError(context, hasAlreadyTriggeredError) {
context.commit(storeMutations.UPDATE_HAS_TRIGGERED_ERROR, hasAlreadyTriggeredError);
},
getValidIdempotencyKey(context) {
if (context.getters.isIdempotencyKeyValid) {
return context.state.idempotencyKeyFields.idempotencyKey;
}
// If invalid, need to regenerate.
const referralCorrelationId = context.state.order?.referralCorrelationId;
if (!referralCorrelationId) {
// Can't generate!
return null;
}
const total = getAmountDue(context.state.order?.lineItems);
const totalInCents = Math.round(total * 100);
if (Number.isNaN(totalInCents)) {
// Can't generate!
return null;
}
const currentTime = new Date();
const nextHour = currentTime.getUTCHours() + 1;
currentTime.setUTCHours(nextHour);
const newId = crypto.randomUUID();
const newKeyInfo = {
idempotencyKey: newId,
referralCorrelationId: referralCorrelationId,
totalInCents: totalInCents,
expiryTime: currentTime,
};
context.commit(storeMutations.UPDATE_IDEMPOTENCY_KEY, newKeyInfo);
return newId;
},
correctIdempotencyKeyExpiry(context, expiryTime) {
if (!context.getters.isIdempotencyKeyValid) {
return;
}
const currentExpiryTime = new Date(context.state.idempotencyKeyFields.expiryTime);
const expiryTimeAsDate = new Date(expiryTime);
if (expiryTimeAsDate.getTime() < currentExpiryTime.getTime()) {
const existingKey = context.state.idempotencyKeyFields;
const newKey = {
referralCorrelationId: existingKey.referralCorrelationId,
totalInCents: existingKey.totalInCents,
idempotencyKey: existingKey.idempotencyKey,
expiryTime: expiryTimeAsDate,
};
context.commit(storeMutations.UPDATE_IDEMPOTENCY_KEY, newKey);
}
},
};
export default createStore({
plugins: [
createPersistedState(),
sharedMutations({
predicate: [...Object.values(storeMutations)],
}),
],
// IMPORTANT: Be VERY careful when modifying these fields for at least a few reasons:
// * The CMS can reference the fields by name
// * Return users may have a previous "version" of the model, and we don't want
// them to have a breaking experience, because the model might have changed.
state,
mutations,
getters,
actions,
});
export function mapTaxedLineItemsToStoreFormat(availableLineItems, storeLineItems) {
// clone the lineItems array because what we're passing in is referencing the store directly
const lineItems = deepClone(storeLineItems);
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;
}
export function getArrayOfAllLineItemsAndChildParts(lineItems) {
let consolidatedLineItemsArray = [];
if (lineItems?.glassParts != null)
consolidatedLineItemsArray = [
...consolidatedLineItemsArray,
...getFlattenedArrayOfLineItemsWithChildParts(lineItems.glassParts),
];
if (lineItems?.supportingItems != null)
consolidatedLineItemsArray = [
...consolidatedLineItemsArray,
...getFlattenedArrayOfLineItemsWithChildParts(lineItems.supportingItems),
];
if (lineItems?.vaps != null)
consolidatedLineItemsArray = [
...consolidatedLineItemsArray,
...getFlattenedArrayOfLineItemsWithChildParts(lineItems.vaps),
];
if (lineItems?.promos != null)
consolidatedLineItemsArray = [
...consolidatedLineItemsArray,
...getFlattenedArrayOfLineItemsWithChildParts(lineItems.promos),
];
return consolidatedLineItemsArray;
}
// Private Functions
function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
return (array ?? []).map((x) => x[propertyName]).filter((x) => x);
}
function getTimeSlotsAdditionalEventData(
provisionalTriggers,
zipCode,
firstAvailableAppointmentDateString,
shopAppointmentType
) {
var numberOfDays = null;
if (firstAvailableAppointmentDateString)
numberOfDays = getDateDifferenceInDays(
new Date().toISOString().split("T")[0],
firstAvailableAppointmentDateString
);
if (shopAppointmentType)
return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ShopAppointmentType:${shopAppointmentType},ProvisionalTriggers:${provisionalTriggers.join(
","
)}`;
else
return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ProvisionalTriggers:${provisionalTriggers.join(
","
)}`;
}
function getHasRecalibrationPart(state) {
return containsRecalParts(state.order.lineItems);
}
function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
if (!arrayOfObjects) return null;
return arrayOfObjects.sort((a, b) => {
if (a[propertyName] < b[propertyName]) return -1;
else if (a[propertyName] > b[propertyName]) return 1;
else return 0;
});
}
function convertGlassPieceNamingForApi(glassArray) {
if (!glassArray || glassArray.length === 0) return [];
// check if array already converted. (likely when a session has been saved previously and then reloaded)
if (glassArray[0].location !== undefined) {
return glassArray;
}
const converted = [];
glassArray.forEach((glass) => {
converted.push({
location: glass.glassLocation,
name: glass.glassName,
});
});
return converted;
}
function convertResultsForApi(resultsArray) {
if (!resultsArray) return [];
const converted = [];
resultsArray.forEach((answer) => {
converted.push({
location: answer.glassLocation,
name: answer.glassName,
result: answer.result,
});
});
return converted;
}
function convertGlassPieceNamingFromApi(glassArray) {
glassArray.forEach((glass) => {
glass.glassLocation = glass.glassPiece.location;
glass.glassName = glass.glassPiece.name;
delete glass.glassPiece;
return glass;
});
return glassArray;
}
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 getFlattenedArrayOfLineItemsWithChildParts(lineItems, childPartRecursiveCall = false) {
let flattenedArray = [];
lineItems?.forEach((lineItem) => {
// this assumes childparts will never be a glass part
lineItem.isChildPart = childPartRecursiveCall;
flattenedArray.push(lineItem);
if (lineItem.childParts) {
flattenedArray = [
...flattenedArray,
...getFlattenedArrayOfLineItemsWithChildParts(lineItem.childParts, true),
];
}
});
return flattenedArray;
}
function getFlattenedLineItemsWithGlassPartTag(lineItems) {
const nonGlassLineItems = [...(lineItems.supportingItems ?? []), ...(lineItems.vaps ?? [])];
const mappedNonGlassLineItems = nonGlassLineItems.map((lineItem) => {
return {
partNumber: lineItem.partNumber,
partType: lineItem.partType,
isGlassPart: false,
};
});
const glassLineItems = [...getFlattenedArrayOfLineItemsWithChildParts(lineItems.glassParts)];
const mappedGlassLineItems = glassLineItems.map((lineItem) => {
return {
partNumber: lineItem.partNumber,
partType: lineItem.partType,
isGlassPart: lineItem.isChildPart ? false : true,
};
});
return [...mappedNonGlassLineItems, ...mappedGlassLineItems];
}
function buildQueryStringParameterFromArrayOfComplexObjects(arrayOfObjects, parameterName) {
let queryStringParameter = "";
for (let i = 0; i < arrayOfObjects.length; i++) {
for (const [key, value] of Object.entries(arrayOfObjects[i])) {
if (value || value === 0) {
queryStringParameter += `${parameterName}[${i}].${key}=${value}&`;
}
}
}
// Remove trailing &
return queryStringParameter.slice(0, -1);
}
function convertGlassPieceToBackEndCompatibleFormat(glassPieces) {
return glassPieces.map((glassPiece) => {
return {
location: glassPiece.glassLocation,
name: glassPiece.glassName,
};
});
}
function renameGlassToReplaceAttributes(glassToReplace) {
let newGlassToReplace = [];
if (glassToReplace) {
newGlassToReplace = glassToReplace.map((item) => {
return { location: item.glassLocation, name: item.glassName };
});
}
return newGlassToReplace;
}
function addGuidToLineItemsIfNotAlreadyThere(lineItems) {
lineItems?.forEach((lineItem) => {
if (!lineItem.id) {
lineItem.id = crypto.randomUUID();
}
if (lineItem.childParts) {
addGuidToLineItemsIfNotAlreadyThere(lineItem.childParts);
}
});
}
function syncLineItemIds(lineItemsWithoutIds, lineItemsWithIds) {
if (!lineItemsWithIds || !lineItemsWithoutIds) {
return;
}
var clonedLineItemsWithIds = deepClone(lineItemsWithIds);
lineItemsWithoutIds.forEach((noId) => {
var matchedLineItemIndex = -1;
clonedLineItemsWithIds.forEach((withId, index) => {
if (noId.partNumber === withId.partNumber && noId.partType === withId.partType) {
matchedLineItemIndex = index;
noId.id = withId.id;
}
});
if (matchedLineItemIndex > -1) {
// Remove the matched line item
clonedLineItemsWithIds.splice(matchedLineItemIndex, 1);
}
});
}
function providersEqual(providerA, providerB) {
return (
providerA.providerNumber === providerB.providerNumber &&
providerA.address?.city === providerB.address?.city &&
providerA.address?.state === providerB.address?.state &&
providerA.address?.streetAddress === providerB.address?.streetAddress &&
providerA.address?.zipCode === providerB.address?.zipCode
);
//TODO: Change back to deepEqual once zipCodeCtu is added to saveSession.
}
function supportingItemsEqual(supportingItemsA, supportingItemsB) {
if (typeof supportingItemsA !== typeof supportingItemsB) {
return false;
}
if (supportingItemsA === null || supportingItemsB === null) {
return supportingItemsA === supportingItemsB;
}
if (supportingItemsA.length != supportingItemsB.length) {
return false;
}
const sortedA = supportingItemsA.slice().sort();
const sortedB = supportingItemsB.slice().sort();
for (let i = 0; i < sortedA.length; i++) {
if (
sortedA[i].partNumber != sortedB[i].partNumber ||
sortedA[i].partType != sortedB[i].partType
) {
return false;
}
}
return true;
}
// This function will verify schedule info is still valid.
// check to see if we have an appointment date on the order object.
// if so, make sure it's not in the past. if in the past, clear schedule info in store.
// if date not in past, then call schedule service to verify appointment is still available.
async function resetScheduleIfUnavailable(context, order, pageNameToLog) {
// lineItems empty can happen when a customer goes all the way through scheduling as cash but then
// switches to insurance AND also switches vehicles during policy lookup. If you call shop-time-slots
// without parts, you get 500 errors so skip the call.
const lineItems = getArrayOfAllLineItemsAndChildParts(order.lineItems);
if (!order.schedule?.date || lineItems.length === 0) {
console.log(new Date() + " no schedule date or lineItems. skip resetSchedule logic.");
console.log(new Date() + " schedule.schedule.date" + JSON.stringify(order.schedule));
console.log(new Date() + " lineItems" + JSON.stringify(order.lineItems));
return;
}
// Date string with slashes is parsed as local time, not UTC. Our date has dashes, '-'.
// If you put any kind of time stamp on the date string with dashes, then it IS parsed as local time.
var aptDate = new Date(order.schedule.date + "T00:00:00");
var curDate = new Date();
curDate.setHours(0, 0, 0, 0);
// if appointment date is in the past, clear schedule
if (aptDate.getTime() < curDate.getTime()) {
context.commit(storeMutations.RESET_SCHEDULE);
return;
}
// create date range to pass to the schedule service to see if our appointment is still available.
var endRange = new Date(aptDate);
endRange.setDate(aptDate.getDate() + 1);
var endDay = "" + endRange.getDate();
var endMonth = "" + (endRange.getMonth() + 1); // 0 based so add 1
const endYear = endRange.getFullYear();
if (endMonth.length < 2) {
endMonth = "0" + endMonth;
}
if (endDay.length < 2) {
endDay = "0" + endDay;
}
const endDate = [endYear, endMonth, endDay].join("-");
let newTimeSlotsResponse;
if (order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE) {
newTimeSlotsResponse = await context.dispatch(
storeActions.GET_MOBILE_TIME_SLOTS,
{
payload: {
startDate: order.schedule.date,
endDate: endDate,
},
pageNameToLog: pageNameToLog,
},
false
);
if (newTimeSlotsResponse?.data.days?.length === 0) {
context.commit(storeMutations.RESET_SCHEDULE);
return;
}
var mobileRouteCodeFound = false;
// if early bird fee is in supporting items then need to check the timeslot to see if offer premium is also still available
if (
order.lineItem?.supportingItems?.findIndex(
(item) => item.partType == PREMIUM_FEE_PART_TYPE
)
) {
newTimeSlotsResponse.data.days?.forEach((day) => {
day.timeSlots.forEach((ts) => {
if (ts.id === order.schedule.routeCode && ts.offerPremium) {
mobileRouteCodeFound = true;
}
});
});
} else {
newTimeSlotsResponse.data.days?.forEach((day) => {
day.timeSlots.forEach((ts) => {
if (ts.id === order.schedule.routeCode) {
mobileRouteCodeFound = true;
}
});
});
}
if (!mobileRouteCodeFound) {
context.commit(storeMutations.RESET_SCHEDULE);
return;
}
} else {
newTimeSlotsResponse = await context.dispatch(
storeActions.GET_SHOP_TIME_SLOTS,
{
payload: {
startDate: order.schedule.date,
endDate: endDate,
shopAppointmentType: order.serviceLocation.appointmentType,
providerNumber: order.serviceLocation.provider.providerNumber,
},
pageNameToLog: pageNameToLog,
},
false
);
if (newTimeSlotsResponse?.data.days?.length === 0) {
context.commit(storeMutations.RESET_SCHEDULE);
return;
}
var routeCodeFound = false;
newTimeSlotsResponse.data.days?.forEach((day) => {
day.timeSlots.forEach((ts) => {
if (ts.id === order.schedule.routeCode) {
routeCodeFound = true;
}
});
});
//reset schedule if jobMin is null because when switching from cash to insurance dynamo returns null for jobMin
if (!routeCodeFound || order.schedule.jobMinMinutes == null) {
context.commit(storeMutations.RESET_SCHEDULE);
return;
}
}
}
function createExternalParameterDefaultState() {
// create default externalParameter state
const externalParameterDefaultState = {
isExternalParameter: externalParameterStatus.NOT_SET,
qsStash: null,
vehicle: {
year: null,
make: null,
model: null,
style: null,
},
vehicleDamage: {
damageType: null,
isRepair: null,
numberOfChips: null,
},
estimate: {
vinSelection: null,
},
serviceZip: {
zipCode: null,
},
quote: {
isInsurance: null,
servicePackage: null,
},
customer: {
emailAddress: null,
phoneNumber: null,
},
};
// set to session storage
saveExternalParameterState(externalParameterDefaultState);
}
function getExternalParameterDefaultState() {
const externalParameterState = window.sessionStorage.getItem(
sessionStorageKeyConstants.EXTERNAL_PARAMETER_STATE
);
if (externalParameterState === null) {
createExternalParameterDefaultState();
}
return JSON.parse(
window.sessionStorage.getItem(sessionStorageKeyConstants.EXTERNAL_PARAMETER_STATE)
);
}
function saveExternalParameterState(externalParameterState) {
window.sessionStorage.setItem(
sessionStorageKeyConstants.EXTERNAL_PARAMETER_STATE,
JSON.stringify(externalParameterState)
);
}
const timeSlotCallFlags = {
shop: false,
mobile: false,
shopV2: false,
mobileV2: false,
};
function checkIfMiscParts(partsOrQuestions) {
if (!partsOrQuestions || partsOrQuestions.length === 0) {
return { PartsNotFound: true };
} else if (
partsOrQuestions.length === 1 &&
partsOrQuestions[0].parts &&
partsOrQuestions[0].parts.length === 1 &&
partsOrQuestions[0].parts[0].partNumber.startsWith("MISC")
) {
return { PartsNotFound: true };
}
return { PartsNotFound: false };
}