Merge branch 'develop' into feature/CSR-2199
This commit is contained in:
commit
c56c1338f7
48 changed files with 983 additions and 338 deletions
|
|
@ -84,6 +84,10 @@ const endpoints = {
|
|||
url: "/parts/api/v1/parts/supporting-items",
|
||||
method: "POST",
|
||||
},
|
||||
GetRecalPart: {
|
||||
url: "/parts/api/v1/parts/recal-parts",
|
||||
method: "GET",
|
||||
},
|
||||
GetAlertReasons: {
|
||||
url: "/location/api/v1/location/alert-reasons",
|
||||
method: "GET",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ const experimentSettings = {
|
|||
SUBMIT_ORDER_ENABLE_PIA: "SubmitOrder_Enable_PIA",
|
||||
IS_EMAIL_OPTIONAL: "isEmailOptional",
|
||||
SERVICE_PACKAGE_DISCOUNT: "OfferServicePackageDiscount",
|
||||
PROMO_ON_PACKAGE: "Offer_Promo_On_Pkg",
|
||||
RECAL_PRICE_REMOVE: "RecalPriceRemove",
|
||||
INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL: "NextGen_InternalInsuranceTabDisplayThreshold",
|
||||
INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL: "NextGen_ExternalInsuranceTabDisplayThreshold",
|
||||
|
|
|
|||
6
src/constants/external-parameters.js
Normal file
6
src/constants/external-parameters.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
const externalParameterStatus = {
|
||||
NOT_SET: null,
|
||||
ACTIVE: 1,
|
||||
INACTIVE: 0,
|
||||
};
|
||||
export { externalParameterStatus };
|
||||
|
|
@ -29,6 +29,19 @@ export function coverageStatusValue(intCoverageStatus) {
|
|||
}
|
||||
}
|
||||
|
||||
export function coverageStatusEnum(strCoverageStatus) {
|
||||
switch (strCoverageStatus) {
|
||||
case coverageStatus.PENDING:
|
||||
return 0;
|
||||
case coverageStatus.NOCOMP:
|
||||
return 1;
|
||||
case coverageStatus.VERIFIED:
|
||||
return 2;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export const coverageType = {
|
||||
NONE: "None",
|
||||
DEDUCTIBLE: "Deductible",
|
||||
|
|
@ -50,3 +63,18 @@ export function coverageTypeValue(intCoverageType) {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function coverageTypeEnum(strCoverageType) {
|
||||
switch (strCoverageType) {
|
||||
case coverageType.NONE:
|
||||
return 0;
|
||||
case coverageType.DEDUCTIBLE:
|
||||
return 1;
|
||||
case coverageType.ITAC:
|
||||
return 2;
|
||||
case coverageType.NOCOMP:
|
||||
return 3;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const partTypeStrings = {
|
|||
FRONT_WIPER: "FRONT WIPER",
|
||||
REAR_WIPER: "REAR WIPER",
|
||||
RAIN_DEFENSE: "RAIN DEFENSE",
|
||||
ADAS_RECALIBRATION: "ADAS RECALIBRATION",
|
||||
RECALIBRATION: "RECALIBRATION",
|
||||
REPLACE_FEE: "REPLACE FEE",
|
||||
RECYCLE_FEE: "RECYCLE FEE",
|
||||
|
|
|
|||
|
|
@ -54,8 +54,10 @@ const storeActions = {
|
|||
REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA: "revalidateOrderPromosAndSaveServerData",
|
||||
GET_INSURANCE_COMPANY_LIST: "getInsuranceCompanyList",
|
||||
GET_BILL_TO_ACCOUNT_NUMBER: "getBillToAccountNumber",
|
||||
GET_RECAL_PARTS_AND_SAVE_TO_LINE_ITEMS: "getRecalPartsAndSaveToLineItems",
|
||||
|
||||
// DEPENDENCY MUTATIONS
|
||||
RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleStateAndDependencies",
|
||||
RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies",
|
||||
RESET_REGISTRATION_STATE_AND_DEPENDENCIES: "resetRegistrationAndDependencies",
|
||||
RESET_PARTS_STATE_AND_DEPENDENCIES: "resetPartsAndDependencies",
|
||||
|
|
|
|||
|
|
@ -602,6 +602,24 @@ function setupMocks({
|
|||
|
||||
if (props) resultingMountOptions.propsData = props;
|
||||
|
||||
if (isShallowMount) {
|
||||
resultingMountOptions.global.stubs = {
|
||||
...(resultingMountOptions.global.stubs ?? {}),
|
||||
textboxQuestion: {
|
||||
template: `<span></span>`,
|
||||
methods: {
|
||||
handleChange: jest.fn(),
|
||||
},
|
||||
},
|
||||
dropdownQuestion: {
|
||||
template: `<span></span>`,
|
||||
methods: {
|
||||
handleChange: jest.fn(),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const wrapper = isShallowMount
|
||||
? shallowMount(addressQuestions, resultingMountOptions)
|
||||
: mount(addressQuestions, resultingMountOptions);
|
||||
|
|
|
|||
|
|
@ -371,6 +371,12 @@ export default {
|
|||
self.addressModel.state = state;
|
||||
self.addressModel.zipCode = zipCode;
|
||||
|
||||
this.$refs.autocomplete.handleChange(streetNumber);
|
||||
this.$refs.apartmentNumberOrBusinessName.handleChange(route);
|
||||
this.$refs.city.handleChange(city);
|
||||
this.$refs.state.handleChange(state);
|
||||
this.$refs.zipCode.handleChange(zipCode);
|
||||
|
||||
if (!this.displayVerificationWarning) {
|
||||
this.displayVerificationWarning = place.partial_match || !isAddressComplete;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@
|
|||
<span>{{ subtotalText }}</span>
|
||||
<span>{{ getLineItemAmount(subTotal, showCoverageAsPending) }}</span>
|
||||
</div>
|
||||
<div class="sales-tax">
|
||||
<div class="sales-tax" v-show="showSalesTax">
|
||||
<span>{{ salesTaxText }}</span>
|
||||
<span>{{ getLineItemAmount(salesTax) }}</span>
|
||||
</div>
|
||||
|
|
@ -188,6 +188,8 @@ export default {
|
|||
insuranceCompanyName: String,
|
||||
showInsuranceCoverageAs: String,
|
||||
shouldHideRecalibration: Boolean,
|
||||
isItac: Boolean,
|
||||
isNoComp: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -305,8 +307,8 @@ export default {
|
|||
if (!this.lineItems || this.lineItems.length < 1) return;
|
||||
|
||||
const lineItemsCopy = deepClone(this.lineItems);
|
||||
lineItemsCopy.supportingItems = lineItemsCopy.supportingItems
|
||||
? baseMixin.methods.filterOutRecalibration(lineItemsCopy?.supportingItems)
|
||||
lineItemsCopy.glassParts = lineItemsCopy.glassParts
|
||||
? baseMixin.methods.filterOutRecalibration(lineItemsCopy?.glassParts)
|
||||
: [];
|
||||
return lineItemsCopy;
|
||||
},
|
||||
|
|
@ -316,6 +318,10 @@ export default {
|
|||
showCoverageAsVerified() {
|
||||
return this.showInsuranceCoverageAs === coverageStatus.VERIFIED;
|
||||
},
|
||||
showSalesTax() {
|
||||
const tax = parseFloat(this.salesTax).toFixed(2);
|
||||
return tax > 0;
|
||||
},
|
||||
currentDeductible() {
|
||||
const deductible = this.insuranceDeductible;
|
||||
if (!(deductible === 0 || deductible > 0)) {
|
||||
|
|
@ -1007,6 +1013,16 @@ export default {
|
|||
},
|
||||
salesTax() {
|
||||
if (!this.lineItems || this.lineItems.length < 1) return;
|
||||
|
||||
if (
|
||||
this.isInsurance &&
|
||||
!this.showCoverageAsVerified &&
|
||||
!this.isItac &&
|
||||
!this.isNoComp
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.isInsurance || !this.shouldHideRecalibration
|
||||
? baseMixin.methods.getSalesTax(this.lineItems) // calculate with recal (if on order)
|
||||
: baseMixin.methods.getSalesTax(this.lineItemsWithoutRecal); // calculated without recal
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export default {
|
|||
return this.leftAlignHeader ? "justify-content-start" : "justify-content-center";
|
||||
},
|
||||
subText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "HeaderSubText");
|
||||
return this.getCmsContent(this.cmsWidgetName, "SubheaderText");
|
||||
},
|
||||
backButtonAccessibleText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "BackButtonAccessibleText");
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import store from "@/store";
|
|||
|
||||
import { applicationConfig } from "@/constants/application-config.js";
|
||||
import { GaCategories, GaActions, GaLabels } from "@/constants/analytics";
|
||||
import { getSessionKeyValue } from "@/helpers/heritage-integration/cookie-helper";
|
||||
import { headerKeys } from "@/constants/header-keys";
|
||||
import axiosResponseInterceptorMessages from "@/constants/axios-response-interceptor-messages.js";
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ export default {
|
|||
const headers = {
|
||||
[headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings),
|
||||
[headerKeys.APPLICATION_NAME]: applicationConfig.APPLICATION_NAME,
|
||||
[headerKeys.SESSION_SEQUENCE_NUMBER]: store.getters.applicationUser?.savedSessionId,
|
||||
[headerKeys.SESSION_SEQUENCE_NUMBER]: getSessionKeyValue(),
|
||||
[headerKeys.REFERRAL_SEQUENCE_NUMBER]: order?.referralSequenceNumber,
|
||||
[headerKeys.TRANSACTION_ID]: crypto.randomUUID(),
|
||||
[headerKeys.EON]: order?.eon,
|
||||
|
|
|
|||
|
|
@ -109,8 +109,10 @@ export async function getImplicitNavigation(toRoute) {
|
|||
export async function navigateToHeritageFunnel({ shouldSaveSession, pageNameToLog }) {
|
||||
const log = getQuerystringParameter(queryStrings.LOG);
|
||||
if (eval(log)) {
|
||||
console.log("------------- Navigate to heritage start -----------------");
|
||||
console.log(new Date() + " applicationConfig: " + JSON.stringify(applicationConfig));
|
||||
console.log(new Date() + " navigateToHeritageFunnel: " + applicationConfig.HERITAGE_FUNNEL);
|
||||
console.log("------------- Navigate to heritage end -----------------");
|
||||
}
|
||||
|
||||
// Create the order (or save existing order) when navigating to Heritage Funnel.
|
||||
|
|
@ -132,6 +134,8 @@ export async function navigateToHeritageFunnel({ shouldSaveSession, pageNameToLo
|
|||
}
|
||||
|
||||
if (
|
||||
(process.env.VUE_APP_HERITAGE_FUNNEL.includes("fixmyglasstest") &&
|
||||
process.env.VUE_APP_CURRENT_ENVIRONMENT === "Localhost") ||
|
||||
(process.env.VUE_APP_HERITAGE_FUNNEL.includes("fixmyglassdev") &&
|
||||
process.env.VUE_APP_CURRENT_ENVIRONMENT === "Localhost") ||
|
||||
(process.env.VUE_APP_HERITAGE_FUNNEL.includes("localhost") &&
|
||||
|
|
|
|||
60
src/helpers/recal-helper.js
Normal file
60
src/helpers/recal-helper.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { deepClone } from "@/helpers/object-helper";
|
||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||
|
||||
const recalPartTypes = [partTypeStrings.RECALIBRATION, partTypeStrings.ADAS_RECALIBRATION];
|
||||
|
||||
export function isRecalPartOrHasChildRecalPart(lineItem) {
|
||||
if (lineItem.childParts && lineItem.childParts.length > 0) {
|
||||
return isRecalPart(lineItem) || containsRecalParts(lineItem.childParts);
|
||||
} else {
|
||||
return isRecalPart(lineItem);
|
||||
}
|
||||
}
|
||||
|
||||
export function isRecalPart(lineItem) {
|
||||
return recalPartTypes.some((type) => lineItem.partType === type);
|
||||
}
|
||||
|
||||
export function containsRecalParts(lineItems) {
|
||||
if (!lineItems) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Array.isArray(lineItems)) {
|
||||
return lineItems.some((li) => isRecalPartOrHasChildRecalPart(li));
|
||||
} else {
|
||||
// complex object form -- flatten and re-call.
|
||||
const flattened = [
|
||||
...(lineItems.glassParts ?? []),
|
||||
...(lineItems.supportingItems ?? []),
|
||||
...(lineItems.vaps ?? []),
|
||||
...(lineItems.promos ?? []),
|
||||
];
|
||||
|
||||
return flattened.some((li) => isRecalPartOrHasChildRecalPart(li));
|
||||
}
|
||||
}
|
||||
|
||||
export function getItemsWithoutRecalParts(lineItems) {
|
||||
const copy = deepClone(lineItems);
|
||||
|
||||
const firstLevelFiltered = copy.filter((li) => !isRecalPart(li));
|
||||
|
||||
const childrenFiltered = firstLevelFiltered.map((li) => {
|
||||
if (li.childParts && li.childParts.length > 0) {
|
||||
li.childParts = getItemsWithoutRecalParts(li.childParts);
|
||||
}
|
||||
|
||||
return li;
|
||||
});
|
||||
|
||||
return childrenFiltered;
|
||||
}
|
||||
|
||||
export function getTopLevelPartsWithRecal(lineItems) {
|
||||
if (!lineItems) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return lineItems.filter((li) => isRecalPartOrHasChildRecalPart(li));
|
||||
}
|
||||
|
|
@ -239,6 +239,15 @@ export function getPackageNameByType(packageType) {
|
|||
return package_names[packageType] || null;
|
||||
}
|
||||
|
||||
export function getDiscountPackageName(discountPackage) {
|
||||
const package_names = {
|
||||
ECON: packageNames.TIER_ONE,
|
||||
STANDARD: packageNames.TIER_TWO,
|
||||
PREMIUM: packageNames.TIER_THREE,
|
||||
};
|
||||
return package_names[discountPackage] || null;
|
||||
}
|
||||
|
||||
function maxTier(tierA, tierB) {
|
||||
if (tierA === packageNames.TIER_THREE || tierB === packageNames.TIER_THREE) {
|
||||
return packageNames.TIER_THREE;
|
||||
|
|
|
|||
|
|
@ -375,6 +375,7 @@ export default {
|
|||
},
|
||||
false
|
||||
);
|
||||
await this.getAndSaveBillToAccountNumber();
|
||||
|
||||
return await this.navigateForward(carsFound);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import questionsPageLayout from "@/fmg-components/layouts/questions-page-layout/
|
|||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import store from "@/store";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
|
|
@ -52,9 +53,20 @@ export default {
|
|||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
// Call the "next" function to complete the transition to this page.
|
||||
next((vm) => {
|
||||
next(async (vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
if (store.getters.externalParameterState?.isExternalParameter) {
|
||||
if (store.getters.externalParameterServiceZip.zipCode) {
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
|
||||
{
|
||||
zipCode: store.getters.externalParameterServiceZip.zipCode,
|
||||
state: null,
|
||||
zipCodeCtu: null,
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ describe("computed properties...", () => {
|
|||
const testValue = wrapper.vm.AppointmentWordingText;
|
||||
|
||||
// Assert
|
||||
expect(testValue).toEqual("wording Text 123, test,<br/> test, AZ 12345");
|
||||
expect(testValue).toEqual("wording Text test, 123,<br/> test, AZ 12345");
|
||||
});
|
||||
test("AppointmentWordingText should return DROP_OFF text in expected format.", () => {
|
||||
//Arrange
|
||||
|
|
@ -419,7 +419,7 @@ describe("computed properties...", () => {
|
|||
const testValue = wrapper.vm.ServiceLocationFullAddress;
|
||||
|
||||
// Assert
|
||||
expect(testValue).toEqual("123, test,<br/> test, AZ 12345");
|
||||
expect(testValue).toEqual("test, 123,<br/> test, AZ 12345");
|
||||
});
|
||||
test("ProviderFullAddress should return text in expected format.", () => {
|
||||
//Arrange
|
||||
|
|
|
|||
|
|
@ -60,10 +60,13 @@
|
|||
v-model="lineItems"
|
||||
:showAsPaid="isPia"
|
||||
servicePackageOptionsCmsName="ServicePackageTitle"
|
||||
:isInsurance="isInsurance"
|
||||
:insuranceDeductible="currentDeductible"
|
||||
:insuranceCompanyName="insuranceCompanyName"
|
||||
:showInsuranceCoverageAs="showInsuranceCoverageAs"
|
||||
:shouldHideRecalibration="shouldHideRecalibration" />
|
||||
:shouldHideRecalibration="shouldHideRecalibration"
|
||||
:isItac="isItac"
|
||||
:isNoComp="isNoComp" />
|
||||
|
||||
<hr class="mb-5" />
|
||||
|
||||
|
|
@ -108,6 +111,7 @@ import { getDisplayTextForDurationLength } from "@/helpers/duration-length-helpe
|
|||
import { experimentSettings } from "@/constants/experiments";
|
||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||
import { containsLineItemWithPartType } from "@/helpers/service-package-helper";
|
||||
import { containsRecalParts } from "@/helpers/recal-helper.js";
|
||||
|
||||
export default {
|
||||
name: "confirmation",
|
||||
|
|
@ -170,10 +174,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
isRecalibrationOnOrder() {
|
||||
return containsLineItemWithPartType(
|
||||
partTypeStrings.RECALIBRATION,
|
||||
this?.lineItems?.supportingItems
|
||||
);
|
||||
return containsRecalParts(this?.lineItems);
|
||||
},
|
||||
shouldHideRecalibration() {
|
||||
return (
|
||||
|
|
@ -313,11 +314,7 @@ export default {
|
|||
}
|
||||
},
|
||||
ServiceLocationFullAddress() {
|
||||
return `${this.ServiceLocationAddress2 ? this.ServiceLocationAddress2 + "," : ""} ${
|
||||
this.ServiceLocationAddress
|
||||
},<br/> ${this.ServiceLocationCity}, ${this.ServiceLocationState} ${
|
||||
this.ServiceLocationZipCode
|
||||
}`;
|
||||
return `${this.ServiceLocationAddress}${this.ServiceLocationAddress2 ? ", " + this.ServiceLocationAddress2 : ""},<br/> ${this.ServiceLocationCity}, ${this.ServiceLocationState} ${this.ServiceLocationZipCode}`;
|
||||
},
|
||||
ProviderFullAddress() {
|
||||
return `${this.ProviderAddress},<br/> ${this.ProviderCity}, ${this.ProviderState} ${this.ProviderZipCode}`;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ export default {
|
|||
|
||||
// Call the "next" function to complete the transition to this page.
|
||||
next((vm) => {
|
||||
//Reload page if serve from bfcache.
|
||||
if (performance.getEntriesByType("navigation")[0].type === "back_forward") {
|
||||
vm.handlePageShow();
|
||||
}
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
vm.originalList = resultMap.insuranceCompanyList;
|
||||
if (store.getters.externalParameterState?.isExternalParameter) {
|
||||
|
|
@ -93,6 +97,9 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
handlePageShow() {
|
||||
window.location.reload();
|
||||
},
|
||||
isCashParentAccountNumber() {
|
||||
return (
|
||||
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER.toString() ===
|
||||
|
|
@ -121,6 +128,20 @@ export default {
|
|||
this.parentAccountNumber.toString(),
|
||||
false
|
||||
);
|
||||
|
||||
const billToAccountNumber = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||
storeActions.GET_BILL_TO_ACCOUNT_NUMBER,
|
||||
{},
|
||||
"insurance-company",
|
||||
false
|
||||
);
|
||||
|
||||
baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER,
|
||||
billToAccountNumber,
|
||||
false
|
||||
);
|
||||
|
||||
navigateToHeritageFunnel({
|
||||
shouldSaveSession: true,
|
||||
pageNameToLog: "insurance-company",
|
||||
|
|
|
|||
|
|
@ -323,6 +323,7 @@ export default {
|
|||
false
|
||||
);
|
||||
|
||||
await this.getAndSaveBillToAccountNumber();
|
||||
return await this.navigateForward();
|
||||
},
|
||||
lookupVin(plate, state) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import questionsPageLayout from "@/fmg-components/layouts/questions-page-layout/
|
|||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import store from "@/store";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
|
|
@ -52,9 +53,21 @@ export default {
|
|||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
// Call the "next" function to complete the transition to this page.
|
||||
next((vm) => {
|
||||
next(async (vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
if (store.getters.externalParameterState?.isExternalParameter) {
|
||||
if (store.getters.externalParameterServiceZip.zipCode) {
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
|
||||
{
|
||||
zipCode: store.getters.externalParameterServiceZip.zipCode,
|
||||
state: null,
|
||||
zipCodeCtu: null,
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import questionsPageLayout from "@/fmg-components/layouts/questions-page-layout/
|
|||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import store from "@/store";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
|
|
@ -52,9 +53,22 @@ export default {
|
|||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
// Call the "next" function to complete the transition to this page.
|
||||
next((vm) => {
|
||||
next(async (vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
if (store.getters.externalParameterState?.isExternalParameter) {
|
||||
if (store.getters.externalParameterServiceZip.zipCode) {
|
||||
const serviceState = store.getters.order.serviceLocation.state;
|
||||
const serviceZipCtu = store.getters.order.serviceLocation.zipCodeCtu;
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
|
||||
{
|
||||
zipCode: store.getters.externalParameterServiceZip.zipCode,
|
||||
state: serviceState ?? null,
|
||||
zipCodeCtu: serviceZipCtu ?? null,
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@
|
|||
:insuranceDeductible="currentDeductible"
|
||||
:insuranceCompanyName="insuranceCompanyName"
|
||||
:showInsuranceCoverageAs="showInsuranceCoverageAs"
|
||||
:shouldHideRecalibration="shouldHideRecalibration" />
|
||||
:shouldHideRecalibration="shouldHideRecalibration"
|
||||
:isItac="isItac"
|
||||
:isNoComp="isNoComp" />
|
||||
|
||||
<hr class="my-5" />
|
||||
|
||||
|
|
@ -76,7 +78,7 @@
|
|||
validationRules="payment-method-required" />
|
||||
|
||||
<alert
|
||||
v-if="!showPaymentMethodQuestions && !forwardClicked"
|
||||
v-if="showHavePaymentReadyAlert"
|
||||
:isDismissible="false"
|
||||
alertClass="alert-info"
|
||||
cmsWidgetName="NoPiaDisclaimerWidget"
|
||||
|
|
@ -153,6 +155,7 @@ import { partTypeStrings } from "@/constants/part-type-strings";
|
|||
import { mapTaxedLineItemsToStoreFormat } from "../../store";
|
||||
import { coverageStatus } from "@/constants/insurance";
|
||||
import { containsLineItemWithPartType } from "@/helpers/service-package-helper";
|
||||
import { containsRecalParts } from "@/helpers/recal-helper";
|
||||
|
||||
defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED));
|
||||
defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED));
|
||||
|
|
@ -586,10 +589,11 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
isRecalibrationOnOrder() {
|
||||
return containsLineItemWithPartType(
|
||||
partTypeStrings.RECALIBRATION,
|
||||
this.$store.getters.order.lineItems?.supportingItems
|
||||
);
|
||||
const order = baseMixin.methods.hasSubmittedOrder()
|
||||
? baseMixin.methods.getSubmittedOrder()
|
||||
: this.$store.getters.order;
|
||||
|
||||
return containsRecalParts(order.lineItems);
|
||||
},
|
||||
shouldHideRecalibration() {
|
||||
return (
|
||||
|
|
@ -626,13 +630,16 @@ export default {
|
|||
},
|
||||
showInsuranceCoverageAs() {
|
||||
if (!this.isInsurance) return null;
|
||||
|
||||
if (this.isNoComp || this.isItac) {
|
||||
return coverageStatus.NOCOMP;
|
||||
} else {
|
||||
return this.hasSubmittedOrder()
|
||||
? this.getSubmittedOrder()?.payment.insuranceCoverage.coverageStatus
|
||||
: this.$store.getters.payment.insuranceCoverage.coverageStatus;
|
||||
}
|
||||
|
||||
if (this.$store.getters.coverageIsVerified) {
|
||||
return coverageStatus.VERIFIED;
|
||||
}
|
||||
|
||||
return coverageStatus.PENDING;
|
||||
},
|
||||
currentDeductible() {
|
||||
return this.hasSubmittedOrder()
|
||||
|
|
@ -674,6 +681,11 @@ export default {
|
|||
|
||||
return false;
|
||||
},
|
||||
showHavePaymentReadyAlert() {
|
||||
return (
|
||||
!this.showPaymentMethodQuestions && !this.forwardClicked && this.totalAmountDue > 0
|
||||
);
|
||||
},
|
||||
totalAmountDue() {
|
||||
return baseMixin.methods.getAmountDue(this.lineItems);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -57,7 +57,9 @@
|
|||
recyclingModalCmsWidgetName="RecycleModal"
|
||||
:insuranceDeductible="currentDeductible"
|
||||
:insuranceCompanyName="insuranceCompanyName"
|
||||
:showInsuranceCoverageAs="showInsuranceCoverageAs" />
|
||||
:showInsuranceCoverageAs="showInsuranceCoverageAs"
|
||||
:isItac="isItac"
|
||||
:isNocomp="isNocomp" />
|
||||
|
||||
<hr class="mb-5" />
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
import { splitCopyOnCMSPlaceHolder } from "@/helpers/cms-content-helper";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { getPromosThatMatchLineItemsOnOrder } from "@/helpers/promotions-helper";
|
||||
import { getArrayOfAllLineItems } from "@/store";
|
||||
import { getArrayOfAllLineItemsAndChildParts } from "@/store";
|
||||
|
||||
const INLINE_IMAGE_TOKEN = "custom:inlineImage";
|
||||
const AFTERPAY_PRICE_TOKEN = "custom:afterpayPrice";
|
||||
|
|
@ -76,7 +76,7 @@ export default {
|
|||
return this.getCmsContent(this.cmsWidgetName, "SubheaderText");
|
||||
},
|
||||
afterpayPrice() {
|
||||
let allLineItems = getArrayOfAllLineItems(this.lineItems);
|
||||
let allLineItems = getArrayOfAllLineItemsAndChildParts(this.lineItems);
|
||||
if (this.lineItems.promos) {
|
||||
allLineItems = allLineItems?.filter((item) => item.partType !== "PROMO_DISCOUNT");
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ export default {
|
|||
});
|
||||
|
||||
if (this.lineItems.promos) {
|
||||
let allLineItems = getArrayOfAllLineItems(this.lineItems);
|
||||
let allLineItems = getArrayOfAllLineItemsAndChildParts(this.lineItems);
|
||||
const promos = getPromosThatMatchLineItemsOnOrder(
|
||||
this.lineItems.promos,
|
||||
allLineItems
|
||||
|
|
|
|||
|
|
@ -65,6 +65,28 @@ jest.mock("@/mixins/base-mixin", () => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const mockExperimentSettings = experimentSettings;
|
||||
|
||||
jest.mock("@/mixins/experiment-mixin.js", () => ({
|
||||
methods: {
|
||||
getSettingValue(settingName) {
|
||||
if (settingName === mockExperimentSettings.SERVICE_PACKAGE_DISCOUNT) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
settingName === mockExperimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL
|
||||
) {
|
||||
return 300;
|
||||
} else if (
|
||||
settingName === mockExperimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL
|
||||
) {
|
||||
return 500;
|
||||
}
|
||||
return "test";
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
filterOutFees: jest.fn().mockImplementation(() => {
|
||||
|
|
@ -73,12 +95,6 @@ const mockMixin = {
|
|||
isFormValid: jest.fn().mockImplementation(() => {
|
||||
return true;
|
||||
}),
|
||||
getSettingValue: jest.fn((settingName) => {
|
||||
if (settingName === experimentSettings.SERVICE_PACKAGE_DISCOUNT) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
},
|
||||
};
|
||||
let mockTierOnePrice = 501;
|
||||
|
|
@ -309,7 +325,7 @@ describe("quote.vue", () => {
|
|||
|
||||
wrapper.vm.$route = { query: { isInsurance: "false" } };
|
||||
|
||||
const isServicePackageDiscount = mockMixin.methods.getSettingValue(
|
||||
const isServicePackageDiscount = experimentMixin.methods.getSettingValue(
|
||||
experimentSettings.SERVICE_PACKAGE_DISCOUNT
|
||||
);
|
||||
|
||||
|
|
@ -364,7 +380,7 @@ describe("quote.vue", () => {
|
|||
//Assert
|
||||
expect(wrapper.vm.isInsuranceSelected).toBe(true);
|
||||
});
|
||||
test("should default to cash if query param 'isInsurance' is false", async () => {
|
||||
test("should use amount threshold if query param 'isInsurance' is false", async () => {
|
||||
//Arrange
|
||||
store.getters = {
|
||||
lineItems: {
|
||||
|
|
@ -391,6 +407,7 @@ describe("quote.vue", () => {
|
|||
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||
},
|
||||
};
|
||||
mockTierOnePrice = 200;
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
|
|
@ -701,7 +718,7 @@ describe("quote.vue", () => {
|
|||
inactivePromos: [],
|
||||
},
|
||||
},
|
||||
externalParameterState: { isExternalParameter: true },
|
||||
externalParameterState: { isExternalParameter: 1 },
|
||||
externalParameterQuote: {
|
||||
isInsurance: true,
|
||||
servicePackage: "glassonly",
|
||||
|
|
@ -758,8 +775,6 @@ function setupMocks({ customMountOptions }) {
|
|||
baseMixin.methods.ResetExternalParamsAndHideModal = jest.fn();
|
||||
baseMixin.methods.isFormValid = jest.fn().mockReturnValue(true);
|
||||
mountOptions.global.mocks["$store"] = store;
|
||||
store.getters.experimentSettings = "test value";
|
||||
|
||||
mountOptions["attachTo"] = document.body;
|
||||
|
||||
const wrapper = shallowMount(quote, mountOptions);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
alertClass="alert-info" />
|
||||
|
||||
<promoModalQuestion
|
||||
class="small mt-6 d-md-flex justify-content-md-center"
|
||||
class="small mt-6 d-flex justify-content-center"
|
||||
v-model="lineItems"
|
||||
:addableVaps="addableVaps"
|
||||
pageName="quote"
|
||||
|
|
@ -69,9 +69,9 @@
|
|||
|
||||
<textBlock
|
||||
cmsWidgetName="quoteDisclaimer"
|
||||
justifyText="left"
|
||||
justifyText="center"
|
||||
typeStyle="caption"
|
||||
class="mt-6" />
|
||||
class="mt-6 quote-disclaimer" />
|
||||
|
||||
<contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" />
|
||||
<contentGroupModal ref="FrontWiperModal" cmsWidgetName="FrontWiperModal" />
|
||||
|
|
@ -135,6 +135,9 @@ import {
|
|||
import { nextTick } from "vue";
|
||||
import { packageNames } from "@/constants/package-names";
|
||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||
import { containsRecalParts } from "@/helpers/recal-helper";
|
||||
import { externalParameterStatus } from "@/constants/external-parameters";
|
||||
|
||||
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
||||
|
||||
const INSURANCE_TAB_TO_DISPLAY_THRESHOLD_DEFAULT = 300;
|
||||
|
|
@ -296,8 +299,9 @@ export default {
|
|||
|
||||
const getIsInsuranceSelectedValue = (availableLineItems, insuranceThreshold) => {
|
||||
const serviceLocationState = store.getters.order.serviceLocation.state;
|
||||
// Override if coming back from QuoteDetails. Remove override after Quote release
|
||||
const isInsuranceOverrideValue = to.query?.isInsurance;
|
||||
|
||||
// usually true when returning from heritage but can be false when returning from heritage on a save quote
|
||||
const isInsuranceFromQueryString = to.query?.isInsurance || to.query?.isinsurance;
|
||||
const defaultIsInsuranceSelectedValue = store.getters.order.payment.isInsurance;
|
||||
const hideRecalCost =
|
||||
experimentMixin.methods
|
||||
|
|
@ -308,72 +312,88 @@ export default {
|
|||
if (
|
||||
serviceLocationState != null &&
|
||||
payWithInsuranceStates.find((item) => item === serviceLocationState)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
else if (isInsuranceOverrideValue != null) {
|
||||
return isInsuranceOverrideValue == "true";
|
||||
} else if (defaultIsInsuranceSelectedValue != null) {
|
||||
return defaultIsInsuranceSelectedValue;
|
||||
} else {
|
||||
if (availableLineItems) {
|
||||
const lineItemsForCalculatingPrice = hideRecalCost
|
||||
? baseMixin.methods.filterOutFees(
|
||||
baseMixin.methods.filterOutRecalibration(availableLineItems) // Strip out recal before filtering out fees
|
||||
)
|
||||
: baseMixin.methods.filterOutFees(availableLineItems);
|
||||
|
||||
return (
|
||||
baseMixin.methods.getTierOnePackagePrice(lineItemsForCalculatingPrice) >
|
||||
insuranceThreshold
|
||||
); // compare base price vs arbitrary threshold (representing insurance price)
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIsInsuranceSelectedValue != null) {
|
||||
return defaultIsInsuranceSelectedValue;
|
||||
}
|
||||
|
||||
if (availableLineItems) {
|
||||
const lineItemsForCalculatingPrice = hideRecalCost
|
||||
? baseMixin.methods.filterOutFees(
|
||||
baseMixin.methods.filterOutRecalibration(availableLineItems) // Strip out recal before filtering out fees
|
||||
)
|
||||
: baseMixin.methods.filterOutFees(availableLineItems);
|
||||
|
||||
if (isInsuranceFromQueryString != null) {
|
||||
if (isInsuranceFromQueryString.toLowerCase() === "true") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
baseMixin.methods.getTierOnePackagePrice(lineItemsForCalculatingPrice) >
|
||||
insuranceThreshold
|
||||
); // compare base price vs arbitrary threshold (representing insurance price)
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
let thresholdToUse = INSURANCE_TAB_TO_DISPLAY_THRESHOLD_DEFAULT;
|
||||
let internalThreshold = experimentMixin.methods.getSettingValue(
|
||||
experimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL
|
||||
);
|
||||
let externalThreshold = experimentMixin.methods.getSettingValue(
|
||||
experimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL
|
||||
);
|
||||
const isExternalParameter = store.getters.externalParameterState?.isExternalParameter;
|
||||
|
||||
if (!store.getters.externalParameterState?.isExternalParameter) {
|
||||
// there are no external parameters
|
||||
// prettier-ignore
|
||||
{
|
||||
const log = getQuerystringParameter(queryStrings.LOG);
|
||||
if (eval(log)) {
|
||||
console.log("------------- quote.vue thresholds start -----------------");
|
||||
console.log(new Date() + " isExternalParameter: " + isExternalParameter);
|
||||
console.log(new Date() + " internalThreshold: " + internalThreshold);
|
||||
console.log(new Date() + " externalThreshold: " + externalThreshold);
|
||||
console.log("------------- quote.vue thresholds end -----------------");
|
||||
}
|
||||
}
|
||||
|
||||
if (isExternalParameter === externalParameterStatus.NOT_SET) {
|
||||
// there are no active or inactive external parameters; use internal threshold
|
||||
if (internalThreshold) thresholdToUse = internalThreshold;
|
||||
|
||||
vm.isInsuranceSelected = getIsInsuranceSelectedValue(
|
||||
vm.availableLineItems,
|
||||
thresholdToUse
|
||||
);
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
} else {
|
||||
// there ARE external parameters
|
||||
|
||||
if (store.getters.externalParameterQuote.isInsurance == true) {
|
||||
// user came from an external source, however, the externalParms may have been reset on service-zip, property-questions, etc...
|
||||
if (eval(store.getters.externalParameterQuote?.isInsurance)) {
|
||||
// did user intentionally select insurance?
|
||||
vm.isInsuranceSelected = true;
|
||||
vm.servicePackage = store.getters.externalParameterQuote.servicePackage;
|
||||
await nextTick();
|
||||
const isValid = await baseMixin.methods.isFormValid(vm.$refs.theForm);
|
||||
if (isValid) {
|
||||
vm.forwardButtonAction();
|
||||
} else {
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
}
|
||||
} else {
|
||||
// did user come from external source (LeadGen)?
|
||||
let externalSource = store.getters.externalParameterSource
|
||||
? store.getters.externalParameterSource
|
||||
: null;
|
||||
|
||||
// Business logic to determine what "external" source is
|
||||
if (externalSource?.includes("LeadGen")) {
|
||||
const externalThreshold = experimentMixin.methods.getSettingValue(
|
||||
experimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL
|
||||
);
|
||||
if (externalThreshold) thresholdToUse = externalThreshold;
|
||||
} else {
|
||||
if (internalThreshold) thresholdToUse = internalThreshold;
|
||||
if (
|
||||
vm.servicePackage != null &&
|
||||
isExternalParameter === externalParameterStatus.ACTIVE
|
||||
) {
|
||||
const isValid = await baseMixin.methods.isFormValid(vm.$refs.theForm);
|
||||
if (isValid) {
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
vm.forwardButtonAction();
|
||||
}
|
||||
}
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
} else {
|
||||
if (externalThreshold) thresholdToUse = externalThreshold;
|
||||
|
||||
vm.isInsuranceSelected = getIsInsuranceSelectedValue(
|
||||
vm.availableLineItems,
|
||||
thresholdToUse
|
||||
|
|
@ -399,10 +419,7 @@ export default {
|
|||
return Object.assign({}, this.lineItems);
|
||||
},
|
||||
isRecalibrationOnOrder() {
|
||||
return containsLineItemWithPartType(
|
||||
partTypeStrings.RECALIBRATION,
|
||||
this?.availableLineItems
|
||||
);
|
||||
return store.getters.isRecalibrationOnOrder;
|
||||
},
|
||||
isServicePackageDiscountOnOrder() {
|
||||
return containsLineItemWithPartType(
|
||||
|
|
@ -417,10 +434,7 @@ export default {
|
|||
);
|
||||
},
|
||||
shouldHideRecalibration() {
|
||||
return (
|
||||
this.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE)?.toLowerCase() ===
|
||||
"true" && this.isRecalibrationOnOrder
|
||||
);
|
||||
return store.getters.shouldHideRecalibration;
|
||||
},
|
||||
showAfterpayBanner() {
|
||||
return (
|
||||
|
|
@ -438,35 +452,21 @@ export default {
|
|||
},
|
||||
arePagePrerequisitesValid() {
|
||||
const payment = store.getters.order.payment;
|
||||
const log = getQuerystringParameter(queryStrings.LOG);
|
||||
if (eval(log)) {
|
||||
console.log("quote.vue pagePrereqs:");
|
||||
console.log(
|
||||
new Date() +
|
||||
" store.getters.order.serviceLocation.zipCode: " +
|
||||
store.getters.order.serviceLocation?.zipCode
|
||||
);
|
||||
console.log(
|
||||
new Date() +
|
||||
" store.getters.order.serviceLocation.zipCodeCtu: " +
|
||||
store.getters.order.serviceLocation?.zipCodeCtu
|
||||
);
|
||||
console.log(
|
||||
new Date() +
|
||||
" store.getters.order.damage.isRepair: " +
|
||||
store.getters.order.damage?.isRepair
|
||||
);
|
||||
console.log(
|
||||
new Date() +
|
||||
" store.getters.order.lineItems?.glassParts: " +
|
||||
JSON.stringify(store.getters.order.lineItems?.glassParts)
|
||||
);
|
||||
console.log(
|
||||
new Date() +
|
||||
" store.getters.order.payment.insuranceCoverage?.isVerified: " +
|
||||
payment?.insuranceCoverage?.isVerified
|
||||
);
|
||||
|
||||
// prettier-ignore
|
||||
{
|
||||
const log = getQuerystringParameter(queryStrings.LOG);
|
||||
if (eval(log)) {
|
||||
console.log("------------- quote.vue pagePrereqs start -----------------");
|
||||
console.log(new Date() + " store.getters.order.serviceLocation.zipCode: " + store.getters.order.serviceLocation?.zipCode);
|
||||
console.log(new Date() +" store.getters.order.serviceLocation.zipCodeCtu: " + store.getters.order.serviceLocation?.zipCodeCtu);
|
||||
console.log(new Date() + " store.getters.order.damage.isRepair: " + store.getters.order.damage?.isRepair);
|
||||
console.log(new Date() + " store.getters.order.lineItems?.glassParts: " + JSON.stringify(store.getters.order.lineItems?.glassParts));
|
||||
console.log(new Date() + " store.getters.order.payment.insuranceCoverage?.isVerified: " + payment?.insuranceCoverage?.isVerified);
|
||||
console.log("------------- quote.vue pagePrereqs end -----------------");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
store.getters.order.serviceLocation.zipCode &&
|
||||
store.getters.order.serviceLocation.zipCodeCtu &&
|
||||
|
|
@ -579,15 +579,14 @@ export default {
|
|||
}
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
const availablePackageNames = this.$refs.servicePackage.servicePackageAnswers;
|
||||
const availablePackageNames = this.$refs.servicePackage?.servicePackageAnswers;
|
||||
var eventLabel = "";
|
||||
availablePackageNames?.forEach((tier) => {
|
||||
if (tier) {
|
||||
let lineItemsToPrice = this.availableLineItems;
|
||||
if (this.isRecalibrationOnOrder && this.shouldHideRecalibration) {
|
||||
lineItemsToPrice = lineItemsToPrice?.filter((item) => {
|
||||
return item.partType != partTypeStrings.RECALIBRATION;
|
||||
});
|
||||
lineItemsToPrice =
|
||||
baseMixin.methods.filterOutRecalibration(lineItemsToPrice);
|
||||
}
|
||||
if (this.isServicePackageDiscountOnOrder) {
|
||||
lineItemsToPrice = lineItemsToPrice?.filter((item) => {
|
||||
|
|
@ -611,12 +610,7 @@ export default {
|
|||
});
|
||||
eventLabel = eventLabel.slice(0, -1);
|
||||
|
||||
this.pushEventToGA(
|
||||
"quote",
|
||||
this.GaActions.SERVICE_PACKAGE_PRICE,
|
||||
eventLabel,
|
||||
true
|
||||
);
|
||||
this.pushEventToGA("quote", this.GaActions.SERVICE_PACKAGE_PRICE, eventLabel, true);
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
|
|
@ -40,7 +40,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -48,7 +48,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -58,7 +58,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
|
|
@ -67,7 +67,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -75,7 +75,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -85,7 +85,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
|
|
@ -94,7 +94,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -102,7 +102,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -112,7 +112,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
|
|
@ -121,7 +121,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -129,7 +129,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -139,7 +139,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
|
|
@ -148,7 +148,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -156,7 +156,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -166,7 +166,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
|
|
@ -175,7 +175,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -183,7 +183,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -193,7 +193,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
|
|
@ -202,7 +202,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -210,7 +210,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
"<ul><li>New replacement glass</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -220,7 +220,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
|
|
@ -229,7 +229,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -237,7 +237,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -247,7 +247,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Economy service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li></ul>",
|
||||
Image: "",
|
||||
FooterText:
|
||||
"{if:custom:frontWipersApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{else}{if:custom:rearWiperApplicableForTierTwo}New wiper blades are not included with Economy service. Because chips can disrupt the glass surface, we recommend new wipers after a repair.{end}{end}",
|
||||
|
|
@ -256,7 +256,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Standard service",
|
||||
SubheaderText: "MOST POPULAR",
|
||||
BodyText:
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
"<ul><li>New replacement windshield</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierTwo}{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierTwo}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
@ -264,7 +264,7 @@ export const mockProcessedCmsContent = {
|
|||
HeaderText: "Premium service",
|
||||
SubheaderText: "",
|
||||
BodyText:
|
||||
"<ul><li>{if:custom:badCustomValue}DO NOT SHOW{end}New replacement windshield</li><li>Expert installation{if:custom:isRecalibrationOnOrder} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
"<ul><li>{if:custom:badCustomValue}DO NOT SHOW{end}New replacement windshield</li><li>Expert installation{if:custom:showRecalInServicePackages} and {textLink:EstimateRecalModal,recalibration}{end}</li><li>Nationwide lifetime warranty</li><li>{if:custom:frontWipersApplicableForTierThree}{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateFrontWiperModal,front wiper blades}{else}New {textLink:EstimateFrontWiperModal,wiper blades}{end}{end}</li><li>{if:custom:rearWiperApplicableForTierThree}New {textLink:EstimateRearWiperModal,rear wiper blade}{end}</li><li>{if:custom:rainDefenseApplicableForTierThree}{textLink:EstimateRainDefenseModal,Rain Defense}™ treatment{end}</li></ul>",
|
||||
Image: "",
|
||||
FooterText: "",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
containsLineItemWithPartType,
|
||||
findLineItemsWithPartType,
|
||||
} from "@/helpers/service-package-helper";
|
||||
import { experimentSettings } from "@/constants/experiments";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||
import { nextTick } from "vue";
|
||||
|
|
@ -19,6 +20,18 @@ jest.mock("@/store", () => ({
|
|||
dispatch: jest.fn(),
|
||||
}));
|
||||
|
||||
const mockExperimentSettings = experimentSettings;
|
||||
|
||||
jest.mock("@/mixins/experiment-mixin.js", () => ({
|
||||
methods: {
|
||||
getSettingValue(settingName) {
|
||||
if (settingName === mockExperimentSettings.PROMO_ON_PACKAGE) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe("service-package-question.vue", () => {
|
||||
beforeEach(async () => {
|
||||
processedCmsContent = inputQuestionWidgetAnswers;
|
||||
|
|
@ -162,6 +175,19 @@ describe("service-package-question.vue", () => {
|
|||
wrapper.vm.servicePackageAnswers[0].buttonAuxillaryCopy.includes("As little as")
|
||||
).toBe(true);
|
||||
});
|
||||
it("should show service package discount when insurance is not selected", () => {
|
||||
// Arrange
|
||||
mockProps.isInsuranceSelected = false;
|
||||
const wrapper = setupMocks({});
|
||||
// Act
|
||||
|
||||
// Assert
|
||||
expect(
|
||||
wrapper.vm.servicePackageAnswers[0].additionalButtonData.Text.includes(
|
||||
"Special: Save $"
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
it("should return [] from nullSafeAvailableLineItems and not error out if availableLineItems is null", () => {
|
||||
// Arrange
|
||||
mockProps.availableLineItems = null;
|
||||
|
|
@ -476,6 +502,8 @@ describe("service-package-question.vue, matching business rules for package disp
|
|||
mockProps.availableLineItems.push(driverFrontWiperLineItem);
|
||||
mockProps.availableLineItems.push(passengerFrontWiperLineItem);
|
||||
mockProps.isRecalibrationOnOrder = true;
|
||||
mockProps.shouldHideRecalibration = false;
|
||||
mockProps.showRecalInServicePackages = true;
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
const wrapper = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import {
|
|||
containsLineItemWithPartType,
|
||||
findLineItemsWithPartType,
|
||||
getPackageNameByType,
|
||||
getDiscountPackageName,
|
||||
} from "@/helpers/service-package-helper";
|
||||
import {
|
||||
getPromosThatMatchLineItemsOnOrder,
|
||||
|
|
@ -35,6 +36,9 @@ import {
|
|||
getPromosWithAddableVaps,
|
||||
getLineItemsThatMatchPromos,
|
||||
} from "@/helpers/promotions-helper";
|
||||
import { containsRecalParts, getItemsWithoutRecalParts } from "@/helpers/recal-helper";
|
||||
import experimentMixin from "@/mixins/experiment-mixin.js";
|
||||
import { experimentSettings } from "@/constants/experiments";
|
||||
|
||||
export default {
|
||||
name: "servicePackageQuestion",
|
||||
|
|
@ -128,16 +132,22 @@ export default {
|
|||
buttonLabelSubCopy: this.getSubheaderTextFromCms(answer.SubWidgetName),
|
||||
buttonBodyCopy: this.getBodyTextFromCms(answer.SubWidgetName),
|
||||
//The package supports service-package-discount if it has the text value in CMS
|
||||
buttonAuxillaryCopy: this.getDiscountedPackagePriceString(
|
||||
answer.Name,
|
||||
this.isServicePackageDiscountOnOrder && answer.Text != ""
|
||||
),
|
||||
buttonAuxillaryCopy: this.isInsuranceSelected
|
||||
? this.getDiscountedPackagePriceString(answer.Name, false)
|
||||
: this.getDiscountedPackagePriceString(
|
||||
answer.Name,
|
||||
this.isServicePackageDiscountOnOrder &&
|
||||
this.discountPackageNames == answer.Name
|
||||
),
|
||||
buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName),
|
||||
additionalButtonData: {
|
||||
strikeThroughPrice: this.getPackagePriceString(answer.Name),
|
||||
servicePackageDiscount:
|
||||
this.isServicePackageDiscountOnOrder && answer.Text != "",
|
||||
Text: answer.Text + this.getServicePackageDiscountPrice(),
|
||||
this.isServicePackageDiscountOnOrder &&
|
||||
this.discountPackageNames == answer.Name,
|
||||
Text: this.isInsuranceSelected
|
||||
? false
|
||||
: "Special: Save $" + this.getServicePackageDiscountPrice(),
|
||||
},
|
||||
}));
|
||||
return modifiedAnswers;
|
||||
|
|
@ -148,6 +158,12 @@ export default {
|
|||
this.nullSafeAvailableLineItems
|
||||
);
|
||||
},
|
||||
discountPackageNames() {
|
||||
const discountServicePackage = experimentMixin.methods.getSettingValue(
|
||||
experimentSettings.PROMO_ON_PACKAGE
|
||||
);
|
||||
return getDiscountPackageName(discountServicePackage);
|
||||
},
|
||||
frontWipersApplicableForTierTwo() {
|
||||
return shouldFrontWipersBeAvailable(
|
||||
this.glassToReplace,
|
||||
|
|
@ -200,6 +216,9 @@ export default {
|
|||
this.nullSafeAvailableLineItems
|
||||
);
|
||||
},
|
||||
showRecalInServicePackages() {
|
||||
return this.isRecalibrationOnOrder && !this.shouldHideRecalibration;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
processIfStatements,
|
||||
|
|
@ -239,9 +258,7 @@ export default {
|
|||
let lineItemsToPrice = [...this.nullSafeAvailableLineItems];
|
||||
|
||||
if (this.isRecalibrationOnOrder && this.shouldHideRecalibration) {
|
||||
lineItemsToPrice = lineItemsToPrice.filter((item) => {
|
||||
return item.partType != partTypeStrings.RECALIBRATION;
|
||||
});
|
||||
lineItemsToPrice = getItemsWithoutRecalParts(lineItemsToPrice);
|
||||
}
|
||||
|
||||
//remove service package discount part
|
||||
|
|
@ -358,8 +375,8 @@ export default {
|
|||
},
|
||||
getCustomValueFromString(str) {
|
||||
switch (str) {
|
||||
case "isRecalibrationOnOrder":
|
||||
return this.isRecalibrationOnOrder;
|
||||
case "showRecalInServicePackages":
|
||||
return this.showRecalInServicePackages;
|
||||
case "frontWipersApplicableForTierTwo":
|
||||
return this.frontWipersApplicableForTierTwo;
|
||||
case "rearWiperApplicableForTierTwo":
|
||||
|
|
|
|||
|
|
@ -1,15 +1,8 @@
|
|||
<template>
|
||||
<div
|
||||
:class="[this.additionalButtonData.Text ? 'discount-text' : '']"
|
||||
v-if="this.additionalButtonData.servicePackageDiscount"
|
||||
v-html="this.additionalButtonData.Text"></div>
|
||||
<baseInputButton v-bind="$props" @buttonClicked="handleAnswerChange" v-model="selectedValue">
|
||||
<div
|
||||
class="package-label"
|
||||
:class="[
|
||||
this.buttonLabelSubCopy ? 'has-subheader' : '',
|
||||
this.additionalButtonData.servicePackageDiscount ? 'has-text' : '',
|
||||
]"
|
||||
:class="[this.buttonLabelSubCopy ? 'has-subheader' : '']"
|
||||
for="testradio">
|
||||
<div class="package-specs">
|
||||
<div v-if="this.additionalButtonData.servicePackageDiscount" class="row">
|
||||
|
|
@ -78,10 +71,19 @@
|
|||
</ul>
|
||||
<!-- End of body text parsing -->
|
||||
<div
|
||||
class="package-footer fw-bold caption ms-n6"
|
||||
class="package-footer fw-bold caption ms-n6 mt-4"
|
||||
v-if="this.buttonFooterCopy"
|
||||
v-html="this.buttonFooterCopy"></div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="
|
||||
this.additionalButtonData.servicePackageDiscount &&
|
||||
this.additionalButtonData.Text
|
||||
"
|
||||
class="special-save-box">
|
||||
<span v-html="this.additionalButtonData.Text"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</baseInputButton>
|
||||
|
|
@ -138,25 +140,18 @@ export default {
|
|||
<style lang="scss">
|
||||
.package-main {
|
||||
.package-wrapper {
|
||||
margin: 0.5rem 0;
|
||||
margin: 1rem 0;
|
||||
@include media-breakpoint-up(md) {
|
||||
margin: 1rem 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
@include media-breakpoint-up(md) {
|
||||
display: flex;
|
||||
min-height: 336px;
|
||||
}
|
||||
//Unique breakpoint for this page only to accommodate price spacing issues
|
||||
//from use of position: absolute on .service-package-discount (per Design Team request)
|
||||
@media only screen and (min-width: 860px) {
|
||||
display: flex;
|
||||
min-height: 276px;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,19 +174,16 @@ export default {
|
|||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
min-height: 60px;
|
||||
max-height: 100px;
|
||||
max-height: 126px;
|
||||
@include media-breakpoint-up(md) {
|
||||
max-height: 500px;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
transition: max-height 0.25s ease-in;
|
||||
|
||||
&.has-subheader {
|
||||
min-height: 80px;
|
||||
}
|
||||
&.has-text {
|
||||
border-radius: 0 0 0.5rem 0.5rem;
|
||||
border: 1px solid $green;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
|
|
@ -245,6 +237,9 @@ export default {
|
|||
background-color: $blue-100;
|
||||
border: 1px solid $blue;
|
||||
max-height: 500px;
|
||||
.special-save-box {
|
||||
background-color: $green-200;
|
||||
}
|
||||
}
|
||||
+ .package-label {
|
||||
&:before {
|
||||
|
|
@ -294,8 +289,8 @@ export default {
|
|||
bottom: 0.75rem;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 1.125rem;
|
||||
margin-left: 1.25rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
span.strikethrough-price {
|
||||
text-decoration: line-through;
|
||||
|
|
@ -316,28 +311,32 @@ export default {
|
|||
&.service-package-discount {
|
||||
color: $green;
|
||||
text-align: end;
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
font-size: 0.875rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
div.strikethrough-discount-price {
|
||||
text-decoration: line-through;
|
||||
margin-right: 0;
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
margin-right: 0.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.75rem;
|
||||
line-height: 20px;
|
||||
color: $gray-500;
|
||||
padding-right: 2px;
|
||||
color: $gray-550;
|
||||
@include media-breakpoint-up(md) {
|
||||
margin-right: 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
div.discount-price {
|
||||
color: $green;
|
||||
font-weight: 600;
|
||||
font-size: 1.625rem;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
position: absolute;
|
||||
bottom: 0.75rem;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
left: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -388,6 +387,21 @@ export default {
|
|||
font-weight: 600;
|
||||
letter-spacing: 0.75px;
|
||||
}
|
||||
.special-save-box {
|
||||
background-color: $green-100;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: auto;
|
||||
margin-left: -2rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.25rem;
|
||||
margin-top: 0.5rem;
|
||||
span {
|
||||
color: $green;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ import timeSlotModalQuestion from "./time-slot-modal-question/time-slot-modal-qu
|
|||
import textBlock from "@/digital-components/text-block/text-block";
|
||||
|
||||
// Supporting files
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
|
|
@ -305,6 +307,22 @@ export default {
|
|||
arePagePrerequisitesValid() {
|
||||
const serviceLocation = store.getters.order.serviceLocation;
|
||||
|
||||
// prettier-ignore
|
||||
{
|
||||
const log = getQuerystringParameter(queryStrings.LOG);
|
||||
if (eval(log)) {
|
||||
console.log("------------- schedule.vue pagePrereqs start -----------------");
|
||||
console.log(new Date() + " store.getters.order.serviceLocation.zipCode: " + serviceLocation.zipCode);
|
||||
console.log(new Date() + " store.getters.order.serviceLocation.zipCodeCtu: " + serviceLocation.zipCodeCtu);
|
||||
console.log(new Date() + " store.getters.order.serviceLocation.appointmentType: " + serviceLocation.appointmentType);
|
||||
console.log(new Date() + " store.getters.order.serviceLocation.provider.providerNumber: " + serviceLocation.provider.providerNumber);
|
||||
console.log(new Date() + " store.getters.payment.isInsurance: " + store.getters.payment?.isInsurance);
|
||||
console.log(new Date() + " store.getters.order.damage.isRepair: " + store.getters.order.damage.isRepair);
|
||||
console.log(new Date() + " store.getters.order.lineItems.glassParts: " + JSON.stringify(store.getters.order.lineItems?.glassParts));
|
||||
console.log("------------- schedule.vue pagePrereqs end -------------------");
|
||||
}
|
||||
}
|
||||
|
||||
const serviceLocationPreReqs =
|
||||
serviceLocation.zipCode &&
|
||||
serviceLocation.zipCodeCtu &&
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@
|
|||
:aria-label="buttonLabel"
|
||||
class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4">
|
||||
<div class="row-one">
|
||||
<span class="m-0 button-label-copy" :class="textPosition">{{
|
||||
<span class="m-0 button-label-copy text-truncate" :class="textPosition">{{
|
||||
buttonLabel
|
||||
}}</span>
|
||||
<span class="m-0 caption ms-1" :class="textPosition">{{
|
||||
<span class="m-0 caption mx-1 text-nowrap" :class="textPosition">{{
|
||||
buttonLabelSubCopy
|
||||
}}</span>
|
||||
<div
|
||||
v-if="displayAvailabilityIndicators"
|
||||
class="availability-indicator rounded-pill"
|
||||
class="availability-indicator rounded-pill text-nowrap"
|
||||
:class="availabilityRatingClass">
|
||||
<div
|
||||
v-if="!isLoaderDisplayed"
|
||||
|
|
|
|||
|
|
@ -167,7 +167,10 @@ export default {
|
|||
if (logFirstShopsDisplayed) {
|
||||
gaAction = this.GaActions.SHOPS_FIRST_DISPLAYED;
|
||||
}
|
||||
if (this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP) {
|
||||
if (
|
||||
this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP ||
|
||||
this.selectedAppointmentType === AppointmentTypeStrings.DROP_OFF
|
||||
) {
|
||||
var shops = mappedData.map((shop) => {
|
||||
if (shop.value.length > 5 && shop.value.startsWith("00")) {
|
||||
return shop.value.substring(1);
|
||||
|
|
@ -179,7 +182,7 @@ export default {
|
|||
this.pushEventToGA(
|
||||
this.GaCategories.SERVICE_LOCATION,
|
||||
gaAction,
|
||||
shops.join("/"),
|
||||
shops.join(","),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -485,6 +485,7 @@ function setupMocks({ customMountOptions, customZipQuery, customZipDataResponse
|
|||
}),
|
||||
setCmsContent: jest.fn(),
|
||||
navigateForwardWithSingleCarMatch: jest.fn(),
|
||||
getAndSaveBillToAccountNumber: jest.fn(),
|
||||
getZipCodeData: jest.fn().mockImplementation(() => {
|
||||
if (customZipDataResponse) {
|
||||
return customZipDataResponse;
|
||||
|
|
|
|||
|
|
@ -132,11 +132,24 @@ export default {
|
|||
|
||||
next(async (vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
|
||||
if (store.getters.externalParameterState?.isExternalParameter) {
|
||||
const isValid = await baseMixin.methods.isFormValid(vm.$refs.theForm);
|
||||
if (isValid) {
|
||||
vm.forwardButtonAction();
|
||||
} else {
|
||||
if (store.getters.externalParameterServiceZip.zipCode) {
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
|
||||
{
|
||||
zipCode: store.getters.externalParameterServiceZip.zipCode,
|
||||
state: null,
|
||||
zipCodeCtu: null,
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
}
|
||||
}
|
||||
|
|
@ -185,6 +198,7 @@ export default {
|
|||
},
|
||||
false
|
||||
);
|
||||
await this.getAndSaveBillToAccountNumber();
|
||||
|
||||
if (!zipCodeData.isValid) {
|
||||
this.displayInvalidZipAlert = true;
|
||||
|
|
|
|||
|
|
@ -157,6 +157,17 @@ export default {
|
|||
if (isValid) {
|
||||
vm.forwardButtonAction();
|
||||
} else {
|
||||
if (store.getters.externalParameterServiceZip.zipCode) {
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
|
||||
{
|
||||
zipCode: store.getters.externalParameterServiceZip.zipCode,
|
||||
state: null,
|
||||
zipCodeCtu: null,
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@ import store from "@/store";
|
|||
import { storeActions } from "@/constants/store-actions.js";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||
import { applicationConfig } from "../../constants/application-config";
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||
|
||||
//define validation rules
|
||||
defineRule("year-required", required(errorMessages.YEAR_REQUIRED));
|
||||
|
|
@ -127,6 +130,12 @@ export default {
|
|||
},
|
||||
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
const log = getQuerystringParameter(queryStrings.LOG);
|
||||
if (eval(log)) {
|
||||
console.log("----------------- applicationConfig start -----------------");
|
||||
console.log(new Date() + JSON.stringify(applicationConfig));
|
||||
console.log("----------------- applicationConfig end -----------------");
|
||||
}
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||
const experimentForLogging = store.getters.applicationUser.experiments.find(
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@ export default {
|
|||
false
|
||||
);
|
||||
|
||||
await this.getAndSaveBillToAccountNumber();
|
||||
return await this.navigateForward();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -446,6 +446,7 @@ export default {
|
|||
}
|
||||
}
|
||||
pushToDataLayerIfDefined({
|
||||
event: "productArray",
|
||||
productArray: {
|
||||
coupon: coupon,
|
||||
discount: discount.toFixed(2),
|
||||
|
|
@ -544,7 +545,11 @@ export default {
|
|||
);
|
||||
}
|
||||
pushToDataLayerIfDefined({
|
||||
eCommerceCart: { products: combinedLineItems, subTotal: parseInt(subtotal) },
|
||||
event: "eCommerceCart",
|
||||
eCommerceCart: {
|
||||
products: combinedLineItems,
|
||||
subTotal: parseInt(subtotal),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
@ -632,6 +637,7 @@ export default {
|
|||
}
|
||||
}
|
||||
pushToDataLayerIfDefined({
|
||||
event: "commissionJunctionGtmData",
|
||||
commissionJunctionGtmData: {
|
||||
cj_commission_junction_event: cjEvent,
|
||||
cj_referral_sequence_number: refSequenceNum,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { queryStrings } from "@/constants/query-strings";
|
|||
import { dynamicStrings } from "@/constants/dynamic-strings";
|
||||
import { partTypeStrings } from "../constants/part-type-strings";
|
||||
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
|
||||
import { getItemsWithoutRecalParts } from "@/helpers/recal-helper";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
|
@ -82,7 +83,7 @@ export default {
|
|||
};
|
||||
},
|
||||
getTierOnePackagePrice(lineItems) {
|
||||
let lineItemsToPrice = lineItems.filter((lineItem) => {
|
||||
let lineItemsToPrice = lineItems?.filter((lineItem) => {
|
||||
return (
|
||||
lineItem.partType != partTypeStrings.FRONT_WIPER &&
|
||||
lineItem.partType != partTypeStrings.REAR_WIPER &&
|
||||
|
|
@ -94,23 +95,20 @@ export default {
|
|||
return totalPrice;
|
||||
},
|
||||
filterOutFees(lineItems) {
|
||||
const filteredLineItems = lineItems.filter((item) => {
|
||||
const filteredLineItems = lineItems?.filter((item) => {
|
||||
return (
|
||||
(!item.partType.includes("FEE") && !item.partType.includes("EARLY BIRD")) ||
|
||||
(item.partType === "REPAIR FEE" && item.partNumber != "SUPPLIES-REPAIR")
|
||||
(!item?.partType?.includes("FEE") && !item?.partType?.includes("EARLY BIRD")) ||
|
||||
(item?.partType === "REPAIR FEE" && item?.partNumber != "SUPPLIES-REPAIR")
|
||||
);
|
||||
});
|
||||
return filteredLineItems;
|
||||
},
|
||||
filterOutRecalibration(lineItems) {
|
||||
const filteredLineItems = lineItems.filter((item) => {
|
||||
return !item.partType.includes(partTypeStrings.RECALIBRATION);
|
||||
});
|
||||
return filteredLineItems;
|
||||
return getItemsWithoutRecalParts(lineItems);
|
||||
},
|
||||
getTotalPriceOfAllLineItemsAndChildParts(lineItems, includeTax) {
|
||||
let totalPrice = 0;
|
||||
lineItems.forEach((lineItem) => {
|
||||
lineItems?.forEach((lineItem) => {
|
||||
totalPrice += this.getTotalLineItemPrice(lineItem, includeTax);
|
||||
if (lineItem.childParts) {
|
||||
totalPrice += this.getTotalPriceOfAllLineItemsAndChildParts(
|
||||
|
|
@ -141,41 +139,43 @@ export default {
|
|||
},
|
||||
getAmountDue(lineItems, includeTax = true) {
|
||||
var amountDue = 0;
|
||||
if (lineItems.glassParts) {
|
||||
if (lineItems?.glassParts) {
|
||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
|
||||
lineItems.glassParts,
|
||||
includeTax
|
||||
);
|
||||
}
|
||||
if (lineItems.supportingItems) {
|
||||
|
||||
if (lineItems?.supportingItems) {
|
||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
|
||||
lineItems.supportingItems,
|
||||
includeTax
|
||||
);
|
||||
}
|
||||
if (lineItems.vaps) {
|
||||
|
||||
const order = this.hasSubmittedOrder() ? this.getSubmittedOrder() : store.getters.order;
|
||||
if (
|
||||
store.getters.coverageIsVerified &&
|
||||
!order.policy.isNoComp &&
|
||||
!order.policy.isItac
|
||||
) {
|
||||
amountDue = order.policy.currentDeductible;
|
||||
}
|
||||
|
||||
if (lineItems?.vaps) {
|
||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
|
||||
lineItems.vaps,
|
||||
includeTax
|
||||
);
|
||||
}
|
||||
if (lineItems.promos) {
|
||||
|
||||
if (lineItems?.promos) {
|
||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
|
||||
lineItems.promos,
|
||||
includeTax
|
||||
);
|
||||
}
|
||||
|
||||
const order = this.hasSubmittedOrder() ? this.getSubmittedOrder() : store.getters.order;
|
||||
|
||||
if (
|
||||
order.payment.insuranceCoverage.isVerified &&
|
||||
!order.policy.isNoComp &&
|
||||
!order.policy.isItac
|
||||
) {
|
||||
amountDue += order.policy.currentDeductible;
|
||||
}
|
||||
|
||||
return ((amountDue * 100) / 100).toFixed(2);
|
||||
},
|
||||
getSubTotal(lineItems) {
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ describe("baseMixin.js", () => {
|
|||
promos: [],
|
||||
};
|
||||
|
||||
const payment = { insuranceCoverage: { isVerified: true } };
|
||||
const payment = { insuranceCoverage: { isVerified: false } };
|
||||
const policy = { isNoComp: false, isItac: false, currentDeductible: 250 };
|
||||
|
||||
store.getters = {
|
||||
|
|
@ -190,7 +190,7 @@ describe("baseMixin.js", () => {
|
|||
|
||||
var amtDue = mixIn.methods.getAmountDue(lineItems);
|
||||
|
||||
expect(amtDue).toEqual("303.00");
|
||||
expect(amtDue).toEqual("53.00");
|
||||
});
|
||||
|
||||
test("getAmountDue should function with a submitted order", () => {
|
||||
|
|
@ -223,7 +223,7 @@ describe("baseMixin.js", () => {
|
|||
promos: [],
|
||||
};
|
||||
|
||||
const payment = { insuranceCoverage: { isVerified: true } };
|
||||
const payment = { insuranceCoverage: { isVerified: false } };
|
||||
const policy = { isNoComp: false, isItac: false, currentDeductible: 250 };
|
||||
|
||||
mixIn.methods.hasSubmittedOrder = jest.fn().mockReturnValue(true);
|
||||
|
|
@ -240,7 +240,7 @@ describe("baseMixin.js", () => {
|
|||
|
||||
var amtDue = mixIn.methods.getAmountDue(lineItems);
|
||||
|
||||
expect(amtDue).toEqual("303.00");
|
||||
expect(amtDue).toEqual("53.00");
|
||||
});
|
||||
|
||||
test("getAmountDue for cash should sum lineitems", () => {
|
||||
|
|
|
|||
|
|
@ -450,7 +450,17 @@ export default {
|
|||
const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions);
|
||||
|
||||
// save to store lineItems.glassParts
|
||||
self.dispatchStoreAction(storeActions.SAVE_GLASS_PARTS, collectedGlassParts, false);
|
||||
await self.dispatchStoreAction(
|
||||
storeActions.SAVE_GLASS_PARTS,
|
||||
collectedGlassParts,
|
||||
false
|
||||
);
|
||||
|
||||
await self.dispatchStoreActionWithLogging(
|
||||
storeActions.GET_RECAL_PARTS_AND_SAVE_TO_LINE_ITEMS,
|
||||
null,
|
||||
currentPage
|
||||
);
|
||||
|
||||
const payment = store.getters.payment;
|
||||
|
||||
|
|
|
|||
|
|
@ -42,5 +42,19 @@ export default {
|
|||
};
|
||||
return vinLookupMethods[vinSelection] || null;
|
||||
},
|
||||
async getAndSaveBillToAccountNumber() {
|
||||
const pageName = this.$options?.name;
|
||||
const billToAccountNumber = await this.dispatchStoreActionWithLogging(
|
||||
storeActions.GET_BILL_TO_ACCOUNT_NUMBER,
|
||||
{},
|
||||
pageName,
|
||||
false
|
||||
);
|
||||
await this.dispatchStoreAction(
|
||||
this.storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER,
|
||||
billToAccountNumber,
|
||||
false
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
|||
import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
|
||||
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
|
||||
import { fmgPageValues, funnelStartPageName } from "@/router/router-constants/fmgPage-values";
|
||||
import { externalParameterStatus } from "@/constants/external-parameters";
|
||||
|
||||
// Heritage integration
|
||||
import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper";
|
||||
|
|
@ -96,8 +97,6 @@ const routes = [
|
|||
);
|
||||
updateOrCreateFunnelCookie();
|
||||
}
|
||||
//Update external parameter state
|
||||
updateExternalParameterState();
|
||||
|
||||
//Affiliate Cookies
|
||||
const affiliateCookies = getAffiliateCookies();
|
||||
|
|
@ -114,6 +113,17 @@ const routes = [
|
|||
to.query.fmgPage
|
||||
);
|
||||
|
||||
//Update external parameter state
|
||||
updateExternalParameterState();
|
||||
|
||||
// clear part related state because heritage selected a new vehicle
|
||||
if (
|
||||
to.query.fmgPage === fmgPageValues.VEHICLE &&
|
||||
eval(getFunnelCookie()?.HasDelayedClaimRegistration)
|
||||
) {
|
||||
store.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||
}
|
||||
|
||||
const pageToRedirectTo = await getPageToRouteExistingOrderTo(to);
|
||||
|
||||
// This logic may determine that the user should be sent to heritage -- if so, do that here.
|
||||
|
|
@ -264,7 +274,10 @@ router.beforeEach(async (to, from, next) => {
|
|||
);
|
||||
// If alert event is on the bus, then display the alert
|
||||
if (alertEvent !== undefined || unknownAlertEvent !== undefined) {
|
||||
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, false);
|
||||
store.commit(
|
||||
storeMutations.UPDATE_IS_EXTERNAL_PARAMETER,
|
||||
externalParameterStatus.INACTIVE
|
||||
);
|
||||
}
|
||||
}
|
||||
// fromPaymentToConfirmation workaround for navigating from an iframe but
|
||||
|
|
@ -315,12 +328,12 @@ router.afterEach(async (to, from) => {
|
|||
analyticsMixin.methods.pushOrderToDataLayer();
|
||||
|
||||
if (to.query.fmgPage == fmgPageValues.CONFIRMATION) {
|
||||
//Push Product Array to Data Layer
|
||||
analyticsMixin.methods.pushProductArrayToDataLayer();
|
||||
|
||||
//Push Ecommerce Cart to Data Layer
|
||||
analyticsMixin.methods.pushECommerceCartToDataLayer();
|
||||
|
||||
//Push Product Array to Data Layer
|
||||
analyticsMixin.methods.pushProductArrayToDataLayer();
|
||||
|
||||
//Push Commission Junction Gtm Data To Data Layer
|
||||
analyticsMixin.methods.pushCommissionJunctionGtmDataToDataLayer();
|
||||
}
|
||||
|
|
@ -540,7 +553,7 @@ async function DisplayPageError() {
|
|||
type: globalEventTypes.Danger,
|
||||
}
|
||||
);
|
||||
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, false);
|
||||
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.INACTIVE);
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
|
||||
|
||||
|
|
@ -621,6 +634,22 @@ function getRedirectedStartPage() {
|
|||
}
|
||||
|
||||
function updateExternalParameterState() {
|
||||
// if there is an existing external parameter state then they have already been through from an external source(LeadGen) and
|
||||
// are returning. clear out prior related things that need to be selected again like parts and damage type.
|
||||
if (
|
||||
store.getters.externalParameterState?.isExternalParameter ==
|
||||
externalParameterStatus.INACTIVE
|
||||
) {
|
||||
store.dispatch(storeActions.RESET_VEHICLE_STATE_AND_DEPENDENCIES);
|
||||
store.dispatch(storeActions.SAVE_SERVICE_ZIP_CODE_INFO, {
|
||||
state: null,
|
||||
zipCode: null,
|
||||
zipCodeCtu: null,
|
||||
});
|
||||
store.dispatch(storeActions.SAVE_EMAIL, null);
|
||||
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||
}
|
||||
|
||||
const externalParameterYear = getQuerystringParameter(queryStrings.VEHICLE_YEAR);
|
||||
const externalParameterMake = getQuerystringParameter(queryStrings.VEHICLE_MAKE);
|
||||
const externalParameterModel = getQuerystringParameter(queryStrings.VEHICLE_MODEL);
|
||||
|
|
@ -639,7 +668,7 @@ function updateExternalParameterState() {
|
|||
externalParameterModel &&
|
||||
externalParameterStyle
|
||||
) {
|
||||
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, true);
|
||||
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, externalParameterStatus.ACTIVE);
|
||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_YEAR, externalParameterYear);
|
||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MAKE, externalParameterMake);
|
||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MODEL, externalParameterModel);
|
||||
|
|
@ -662,8 +691,10 @@ function updateExternalParameterState() {
|
|||
);
|
||||
}
|
||||
}
|
||||
if (externalParameterZipCode && externalParameterEmail) {
|
||||
if (externalParameterZipCode) {
|
||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_ZIP_CODE, externalParameterZipCode);
|
||||
}
|
||||
if (externalParameterEmail) {
|
||||
store.commit(
|
||||
storeMutations.UPDATE_EXTERNAL_PARAMETER_EMAIL_ADDRESS,
|
||||
externalParameterEmail
|
||||
|
|
|
|||
|
|
@ -36,9 +36,15 @@ import sharedMutations from "./vuex-shared-mutations/vuexSharedMutations";
|
|||
import {
|
||||
coverageStatus,
|
||||
coverageStatusValue,
|
||||
coverageStatusEnum,
|
||||
coverageType,
|
||||
coverageTypeValue,
|
||||
coverageTypeEnum,
|
||||
} from "@/constants/insurance";
|
||||
import { containsRecalParts, getTopLevelPartsWithRecal } from "@/helpers/recal-helper";
|
||||
import { externalParameterStatus } from "@/constants/external-parameters";
|
||||
import { experimentSettings } from "@/constants/experiments";
|
||||
import experimentMixin from "@/mixins/experiment-mixin.js";
|
||||
|
||||
// Export State
|
||||
const getDefaultState = () => {
|
||||
|
|
@ -473,10 +479,6 @@ export const mutations = {
|
|||
externalParameterState.quote.servicePackage = servicePackage;
|
||||
saveExternalParameterState(externalParameterState);
|
||||
},
|
||||
updateExternalParameterSource(state, source) {
|
||||
externalParameterState.source = source;
|
||||
saveExternalParameterState(externalParameterState);
|
||||
},
|
||||
//RESET ExternalParameter MUTATIONS
|
||||
resetExternalParameterVehicleState(state) {
|
||||
externalParameterState.vehicle.year = null;
|
||||
|
|
@ -503,16 +505,11 @@ export const mutations = {
|
|||
saveExternalParameterState(externalParameterState);
|
||||
},
|
||||
resetExternalParameterQuoteState(state) {
|
||||
externalParameterState.quote.isInsurance = null;
|
||||
externalParameterState.quote.servicePackage = null;
|
||||
saveExternalParameterState(externalParameterState);
|
||||
},
|
||||
resetExternalParameterSourceState(state) {
|
||||
externalParameterState.source = null;
|
||||
saveExternalParameterState(externalParameterState);
|
||||
},
|
||||
resetIsExternalParameter(state) {
|
||||
externalParameterState.isExternalParameter = null;
|
||||
externalParameterState.isExternalParameter = externalParameterStatus.INACTIVE;
|
||||
saveExternalParameterState(externalParameterState);
|
||||
},
|
||||
|
||||
|
|
@ -682,7 +679,17 @@ export const mutations = {
|
|||
sessionInformation.order.serviceLocation.provider?.address?.zipCodeCtu;
|
||||
state.order.serviceLocation.techNotes = sessionInformation.order.serviceLocation.techNotes;
|
||||
|
||||
state.order.payment.isInsurance = sessionInformation.order.payment.isInsurance;
|
||||
// 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 &&
|
||||
!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
|
||||
|
|
@ -772,6 +779,24 @@ export const getters = {
|
|||
);
|
||||
return !!nonWindshieldItems?.length;
|
||||
},
|
||||
coverageIsVerified: (state) => {
|
||||
let order;
|
||||
if (window.sessionStorage.getItem("submittedOrder") !== null) {
|
||||
order = JSON.parse(window.sessionStorage.getItem("submittedOrder"));
|
||||
} 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;
|
||||
},
|
||||
|
|
@ -793,6 +818,13 @@ export const getters = {
|
|||
|
||||
return false;
|
||||
},
|
||||
shouldHideRecalibration: (state) => {
|
||||
return (
|
||||
experimentMixin.methods
|
||||
.getSettingValue(experimentSettings.RECAL_PRICE_REMOVE)
|
||||
?.toLowerCase() === "true" && getters.isRecalibrationOnOrder
|
||||
);
|
||||
},
|
||||
areRearWipersOnOrder: (state) => {
|
||||
return !!state.order.lineItems.vaps?.some(
|
||||
(vap) => vap.partType.toUpperCase() === partTypeStrings.REAR_WIPER.toUpperCase()
|
||||
|
|
@ -894,12 +926,12 @@ export const getters = {
|
|||
.filter((x) => !!x.isActive)
|
||||
.map((x) => x.settings)
|
||||
.reduce((r, c) => Object.assign(r, c), {}) ?? {},
|
||||
|
||||
isVerifiedAndDeductibleZeroConfirmed: (state) => {
|
||||
// used as a CMS variable on /payment-method, needed for FunnelSubHeaderWidget on cart pages
|
||||
if (
|
||||
(state.order.policy.currentDeductible === 0 ||
|
||||
state.order.policy.currentDeductible > 0) &&
|
||||
state.order.payment.insuranceCoverage.coverageStatus === coverageStatus.VERIFIED &&
|
||||
state.order.policy.currentDeductible === 0 &&
|
||||
getters.coverageIsVerified(state) &&
|
||||
!state.order.policy.isNoComp
|
||||
) {
|
||||
return true;
|
||||
|
|
@ -915,7 +947,7 @@ export const getters = {
|
|||
externalParameterQuote: (state) => externalParameterState?.quote,
|
||||
externalParameterServiceZip: (state) => externalParameterState?.serviceZip,
|
||||
externalParameterEstimate: (state) => externalParameterState?.estimate,
|
||||
externalParameterSource: (state) => externalParameterState?.source,
|
||||
isExternalParameter: (state) => externalParameterState?.isExternalParameter,
|
||||
};
|
||||
|
||||
function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
||||
|
|
@ -1121,6 +1153,12 @@ export const actions = {
|
|||
},
|
||||
|
||||
// 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);
|
||||
|
||||
|
|
@ -1531,15 +1569,38 @@ export const actions = {
|
|||
},
|
||||
|
||||
getMobileFeePart(context, { pageNameToLog }) {
|
||||
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
|
||||
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 =
|
||||
order.serviceLocation?.provider?.address?.zipCode ?? order.serviceLocation?.zipCode;
|
||||
|
||||
var providerNumber =
|
||||
order.serviceLocation?.provider?.providerNumber ?? order.serviceLocation?.zipCodeCtu;
|
||||
if (providerNumber.startsWith("00") && providerNumber.length > 5) {
|
||||
providerNumber = providerNumber.substring(1);
|
||||
}
|
||||
|
||||
var endPoint = `${endpoints.GetMobileFeePart.url}/?serviceType=${serviceType}&facilityType=${facilityType}&parentAccountNumber=${parentAccountNumber}&billToAccountNumber=${billToAccountNumber}&providerNumber=${providerNumber}&isItacOptimized=${isItacOptimized}&zipCode=${zipCode}`;
|
||||
if (coverageStatus) {
|
||||
endPoint = `${endPoint}&coverageStatus=${coverageStatus}`;
|
||||
}
|
||||
|
||||
if (coverageType) {
|
||||
endPoint = `${endPoint}&coverageType=${coverageType}`;
|
||||
}
|
||||
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetMobileFeePart.method,
|
||||
endpoint: `${endpoints.GetMobileFeePart.url}/${damageType}/${parentAccountNumber}/${billToAccountNumber}`,
|
||||
endpoint: endPoint,
|
||||
logApiCall: true,
|
||||
pageNameToLog: pageNameToLog,
|
||||
});
|
||||
|
|
@ -1566,16 +1627,21 @@ export const actions = {
|
|||
},
|
||||
|
||||
getServiceabilityDetails(context, { payload: { serviceZipCode }, pageNameToLog }) {
|
||||
const lineItemsWithOnlyPartNumbers = context.getters.order.lineItems.supportingItems?.map(
|
||||
const escapeRecalibrationType = (rt) => rt.split("&").join("%26");
|
||||
|
||||
const partialLineItemsObjects = context.getters.order.lineItems.glassParts?.map(
|
||||
(lineItem) => ({
|
||||
partNumber: lineItem.partNumber,
|
||||
recalibrationType: lineItem.recalibrationType
|
||||
? escapeRecalibrationType(lineItem.recalibrationType)
|
||||
: undefined,
|
||||
})
|
||||
);
|
||||
|
||||
var lineItems = null;
|
||||
if (lineItemsWithOnlyPartNumbers) {
|
||||
if (partialLineItemsObjects) {
|
||||
lineItems = buildQueryStringParameterFromArrayOfComplexObjects(
|
||||
lineItemsWithOnlyPartNumbers,
|
||||
partialLineItemsObjects,
|
||||
"lineItems"
|
||||
);
|
||||
}
|
||||
|
|
@ -1590,7 +1656,12 @@ export const actions = {
|
|||
"glassPieces"
|
||||
);
|
||||
|
||||
var endPoint = `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}`;
|
||||
const parentAccountNumber =
|
||||
context.getters.order.payment.parentAccountNumber ??
|
||||
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER;
|
||||
const referralSequenceNumber = context.getters.order.referralSequenceNumber;
|
||||
|
||||
var endPoint = `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&parentAccountNumber=${parentAccountNumber}&referralSequenceNumber=${referralSequenceNumber}&applicationName=${applicationConfig.ANALYTICS_APPLICATION_NAME}`;
|
||||
if (lineItems) {
|
||||
endPoint += `&${lineItems}`;
|
||||
}
|
||||
|
|
@ -1609,11 +1680,26 @@ export const actions = {
|
|||
|
||||
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}`;
|
||||
}
|
||||
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetProviders.method,
|
||||
endpoint: `${endpoints.GetProviders.url}/${serviceZipCode}/${damageType}/${shopRadiusInMiles}`,
|
||||
endpoint: url,
|
||||
logApiCall: true,
|
||||
pageNameToLog: pageNameToLog,
|
||||
});
|
||||
|
|
@ -2579,9 +2665,10 @@ export const actions = {
|
|||
carId: order.vehicle.carId,
|
||||
correlationId: order.referralCorrelationId,
|
||||
eon: order.eon,
|
||||
isInsurance: order.payment.isInsurance,
|
||||
isRepair: order.damage.isRepair,
|
||||
glassToReplace: renameGlassToReplaceAttributes(order.damage.glassToReplace),
|
||||
lineItemsOnOrder: getArrayOfAllLineItems(lineItemsToUse),
|
||||
lineItemsOnOrder: getArrayOfAllLineItemsAndChildParts(lineItemsToUse),
|
||||
parentAccountNumber: useDefaultCashParentAccount
|
||||
? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER
|
||||
: order.payment.parentAccountNumber,
|
||||
|
|
@ -2651,9 +2738,10 @@ export const actions = {
|
|||
carId: order.vehicle.carId,
|
||||
correlationId: order.referralCorrelationId,
|
||||
eon: order.eon,
|
||||
isInsurance: order.payment.isInsurance,
|
||||
isRepair: order.damage.isRepair,
|
||||
glassToReplace: renameGlassToReplaceAttributes(order.damage.glassToReplace),
|
||||
lineItemsOnOrder: getArrayOfAllLineItems(lineItemsToUse),
|
||||
lineItemsOnOrder: getArrayOfAllLineItemsAndChildParts(lineItemsToUse),
|
||||
parentAccountNumber: useDefaultCashParentAccount
|
||||
? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER
|
||||
: order.payment.parentAccountNumber,
|
||||
|
|
@ -2721,10 +2809,8 @@ export const actions = {
|
|||
pageNameToLog,
|
||||
}
|
||||
) {
|
||||
// Cash orders default to 87291 - update if/when more detailed
|
||||
// billToAccountNumbers are needed for cash
|
||||
if (parentAccountNumber == applicationConfig.CASH_PARENT_ACCOUNT_NUMBER) {
|
||||
return applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER;
|
||||
if (!parentAccountNumber) {
|
||||
parentAccountNumber = applicationConfig.CASH_PARENT_ACCOUNT_NUMBER;
|
||||
}
|
||||
const queryString =
|
||||
`ParentAccountNumber=${parentAccountNumber}` +
|
||||
|
|
@ -2885,7 +2971,6 @@ export const actions = {
|
|||
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_SOURCE_STATE);
|
||||
context.commit(storeMutations.RESET_IS_EXTERNAL_PARAMETER);
|
||||
}
|
||||
},
|
||||
|
|
@ -2903,6 +2988,49 @@ export const actions = {
|
|||
externalParameterMMS.externalParameterStyle
|
||||
);
|
||||
},
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default createStore({
|
||||
|
|
@ -2925,34 +3053,7 @@ export default createStore({
|
|||
// Private Functions
|
||||
|
||||
function getHasRecalibrationPart(state) {
|
||||
var hasRequiresRecalibration =
|
||||
getNonFalseValuesOfPropertyInArrayOfObjects(
|
||||
state.order.lineItems.glassParts,
|
||||
"requiresRecalibration"
|
||||
)?.length > 0;
|
||||
var hasRecalibrationType =
|
||||
getNonFalseValuesOfPropertyInArrayOfObjects(
|
||||
state.order.lineItems.glassParts,
|
||||
"recalibrationType"
|
||||
)?.length > 0;
|
||||
|
||||
if (hasRequiresRecalibration) {
|
||||
if (hasRecalibrationType) {
|
||||
// Has both 'requiresRecalibration' and 'recalibrationType' and 'recalibrationType'
|
||||
return (
|
||||
getNonFalseValuesOfPropertyInArrayOfObjects(
|
||||
state.order.lineItems.glassParts,
|
||||
"recalibrationType"
|
||||
)[0].toLowerCase() != "unknown"
|
||||
);
|
||||
} else {
|
||||
// Has 'requiresRecalibration' but no 'recalibrationType' at all
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Does not have 'requiresRecalibration'
|
||||
return false;
|
||||
}
|
||||
return containsRecalParts(state.order.lineItems);
|
||||
}
|
||||
|
||||
function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
|
||||
|
|
@ -3120,32 +3221,46 @@ export function mapTaxedLineItemsToStoreFormat(availableLineItems, storeLineItem
|
|||
return lineItems;
|
||||
}
|
||||
|
||||
export function getArrayOfAllLineItems(lineItems) {
|
||||
export function getArrayOfAllLineItemsAndChildParts(lineItems) {
|
||||
let consolidatedLineItemsArray = [];
|
||||
|
||||
if (lineItems.glassParts != null)
|
||||
consolidatedLineItemsArray = [...consolidatedLineItemsArray, ...lineItems.glassParts];
|
||||
consolidatedLineItemsArray = [
|
||||
...consolidatedLineItemsArray,
|
||||
...getFlattenedArrayOfLineItemsWithChildParts(lineItems.glassParts),
|
||||
];
|
||||
|
||||
if (lineItems.supportingItems != null)
|
||||
consolidatedLineItemsArray = [...consolidatedLineItemsArray, ...lineItems.supportingItems];
|
||||
consolidatedLineItemsArray = [
|
||||
...consolidatedLineItemsArray,
|
||||
...getFlattenedArrayOfLineItemsWithChildParts(lineItems.supportingItems),
|
||||
];
|
||||
|
||||
if (lineItems.vaps != null)
|
||||
consolidatedLineItemsArray = [...consolidatedLineItemsArray, ...lineItems.vaps];
|
||||
consolidatedLineItemsArray = [
|
||||
...consolidatedLineItemsArray,
|
||||
...getFlattenedArrayOfLineItemsWithChildParts(lineItems.vaps),
|
||||
];
|
||||
|
||||
if (lineItems.promos != null)
|
||||
consolidatedLineItemsArray = [...consolidatedLineItemsArray, ...lineItems.promos];
|
||||
consolidatedLineItemsArray = [
|
||||
...consolidatedLineItemsArray,
|
||||
...getFlattenedArrayOfLineItemsWithChildParts(lineItems.promos),
|
||||
];
|
||||
|
||||
return consolidatedLineItemsArray;
|
||||
}
|
||||
|
||||
function getFlattenedArrayOfLineItemsWithChildParts(lineItems) {
|
||||
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),
|
||||
...getFlattenedArrayOfLineItemsWithChildParts(lineItem.childParts, true),
|
||||
];
|
||||
}
|
||||
});
|
||||
|
|
@ -3168,7 +3283,7 @@ function getFlattenedLineItemsWithGlassPartTag(lineItems) {
|
|||
return {
|
||||
partNumber: lineItem.partNumber,
|
||||
partType: lineItem.partType,
|
||||
isGlassPart: true,
|
||||
isGlassPart: lineItem.isChildPart ? false : true,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
@ -3212,6 +3327,9 @@ function addGuidToLineItemsIfNotAlreadyThere(lineItems) {
|
|||
if (!lineItem.id) {
|
||||
lineItem.id = crypto.randomUUID();
|
||||
}
|
||||
if (lineItem.childParts) {
|
||||
addGuidToLineItemsIfNotAlreadyThere(lineItem.childParts);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -3393,7 +3511,7 @@ async function resetScheduleIfUnavailable(context, order, pageNameToLog) {
|
|||
function createExternalParameterDefaultState() {
|
||||
// create default externalParameter state
|
||||
const externalParameterDefaultState = {
|
||||
isExternalParameter: null,
|
||||
isExternalParameter: externalParameterStatus.NOT_SET,
|
||||
vehicle: {
|
||||
year: null,
|
||||
make: null,
|
||||
|
|
@ -3416,7 +3534,6 @@ function createExternalParameterDefaultState() {
|
|||
isInsurance: null,
|
||||
servicePackage: null,
|
||||
},
|
||||
source: null,
|
||||
};
|
||||
// set to session storage
|
||||
saveExternalParameterState(externalParameterDefaultState);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { storeActions } from "@/constants/store-actions";
|
|||
import { experimentTriggers } from "@/constants/experiments";
|
||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
||||
import { coverageStatus } from "../constants/insurance";
|
||||
|
||||
// Mock global method
|
||||
globalMethods.callHttpClient = jest.fn();
|
||||
|
|
@ -2935,7 +2934,10 @@ describe("Actions", () => {
|
|||
// Arrange
|
||||
const context = state;
|
||||
const promoCode = "testPromo";
|
||||
const lineItemsToUse = { vaps: [{ partNumber: 1 }], promos: [2] };
|
||||
const lineItemsToUse = {
|
||||
vaps: [{ partNumber: 1 }],
|
||||
promos: [{ promoCode: "1wiper0" }],
|
||||
};
|
||||
const addableVaps = [{ partNumber: "addableVap" }];
|
||||
|
||||
context["getters"] = {
|
||||
|
|
@ -2999,7 +3001,7 @@ describe("Actions", () => {
|
|||
{ partNumber: "SBB22", id: "GUID1" },
|
||||
{ partNumber: "SBB22", id: "GUID2" },
|
||||
],
|
||||
promos: [2],
|
||||
promos: [{ promoCode: "1wiper0" }],
|
||||
};
|
||||
const addableVaps = [{ partNumber: "SBB22" }, { partNumber: "SBB22" }];
|
||||
|
||||
|
|
@ -3059,7 +3061,10 @@ describe("Actions", () => {
|
|||
// Arrange
|
||||
const context = state;
|
||||
const promoCode = "testPromo";
|
||||
const lineItemsToUse = { vaps: [{ partNumber: 1 }], promos: [2] };
|
||||
const lineItemsToUse = {
|
||||
vaps: [{ partNumber: 1 }],
|
||||
promos: [{ promoCode: "1wiper0" }],
|
||||
};
|
||||
const addableVaps = [{ partNumber: "addableVap" }];
|
||||
|
||||
context["getters"] = {
|
||||
|
|
@ -3140,7 +3145,7 @@ describe("Actions", () => {
|
|||
referralSequenceNumber: "test",
|
||||
lineItems: {
|
||||
vaps: [{ partNumber: 1 }],
|
||||
promos: [2],
|
||||
promos: [{ promoCode: "1wiper0" }],
|
||||
serverData: "test",
|
||||
},
|
||||
},
|
||||
|
|
@ -3152,7 +3157,10 @@ describe("Actions", () => {
|
|||
|
||||
crypto.randomUUID = jest.fn(() => "GUID");
|
||||
|
||||
const expectedLineItemsOnOrder = [{ partNumber: 1, id: "GUID" }, 2];
|
||||
const expectedLineItemsOnOrder = [
|
||||
{ partNumber: 1, isChildPart: false, id: "GUID" },
|
||||
{ promoCode: "1wiper0", isChildPart: false },
|
||||
];
|
||||
|
||||
// Act
|
||||
actions.validateOrderPromoAndSaveServerData(context, {
|
||||
|
|
@ -3200,7 +3208,7 @@ describe("Actions", () => {
|
|||
referralSequenceNumber: "test",
|
||||
lineItems: {
|
||||
vaps: [{ partNumber: 1 }],
|
||||
promos: [2],
|
||||
promos: [{ promoCode: "1wiper0" }],
|
||||
serverData: "test",
|
||||
},
|
||||
},
|
||||
|
|
@ -3258,7 +3266,7 @@ describe("Actions", () => {
|
|||
referralSequenceNumber: "test",
|
||||
lineItems: {
|
||||
vaps: [{ partNumber: 1 }],
|
||||
promos: [2],
|
||||
promos: [{ promoCode: "1wiper0" }],
|
||||
serverData: "test",
|
||||
},
|
||||
},
|
||||
|
|
@ -3350,9 +3358,9 @@ describe("Actions", () => {
|
|||
const context = state;
|
||||
context.commit = jest.fn(() => {});
|
||||
|
||||
const activePromosToUse = [{ promoCode: "providedPromo" }];
|
||||
const activePromosToUse = [{ promoCode: "providedPromo", isChildPart: false }];
|
||||
const inactivePromosToUse = ["providedInactivePromo"];
|
||||
const vapsProvided = [{ id: 123 }];
|
||||
const vapsProvided = [{ id: 123, isChildPart: false }];
|
||||
const lineItemsToUse = { vaps: vapsProvided };
|
||||
|
||||
context["getters"] = {
|
||||
|
|
@ -3440,8 +3448,8 @@ describe("Actions", () => {
|
|||
referralSequenceNumber: "test",
|
||||
lineItems: {
|
||||
serverData: "test",
|
||||
promos: [{ promoCode: "test" }],
|
||||
vaps: [{ partNumber: "testVap", id: "providedId" }],
|
||||
promos: [{ promoCode: "test", isChildPart: false }],
|
||||
vaps: [{ partNumber: "testVap", isChildPart: false, id: "providedId" }],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -3950,6 +3958,111 @@ describe("Getters", () => {
|
|||
mutations.updateVaps(storeState, mockStateValues.funnelVaps);
|
||||
mutations.updateGlassToReplace(storeState, mockStateValues.glassToReplace);
|
||||
|
||||
//Assert
|
||||
expect(getters.experimentOrder(storeState)).toEqual({
|
||||
funnelVehicleYear: mockStateValues.vehicleYear,
|
||||
funnelVehicleMake: mockStateValues.vehicleMake,
|
||||
funnelVehicleModel: mockStateValues.vehicleModel,
|
||||
funnelVehicleStyle: mockStateValues.vehicleStyle,
|
||||
funnelIsRepair: mockStateValues.isRepair,
|
||||
funnelNumberOfChips: mockStateValues.numberOfChips,
|
||||
funnelCarId: mockStateValues.carId,
|
||||
funnelServiceCity: mockStateValues.serviceCity,
|
||||
funnelServiceState: mockStateValues.serviceState,
|
||||
funnelServiceZipCode: mockStateValues.serviceZipCode,
|
||||
funnelParentAccountNumber: mockStateValues.parentAccountNumber,
|
||||
funnelIsCoverageVerified: mockStateValues.isCoverageVerified,
|
||||
funnelOrderPartNumbers: ["WINDSHIELDPARTNUMBER"],
|
||||
funnelOrderPartTypes: ["ADAS, maybe"],
|
||||
funnelHasRecalibrationPart: false,
|
||||
funnelSelectedMultiGlass: false,
|
||||
funnelSelectedWindshieldGlass: true,
|
||||
funnelSelectedBackGlass: false,
|
||||
funnelSelectedDriverSideGlass: false,
|
||||
funnelSelectedPassengerSideGlass: false,
|
||||
funnelProviderNumber: mockStateValues.funnelProviderNumber,
|
||||
funnelReferralType: mockStateValues.funnelReferralType,
|
||||
funnelServiceZipCodeCtu: mockStateValues.funnelServiceZipCodeCtu,
|
||||
});
|
||||
});
|
||||
|
||||
test("Single windshield with recalibration child part > return correct experimentOrder values", () => {
|
||||
// Arrange
|
||||
const storeState = state;
|
||||
const mockStateValues = {
|
||||
vehicleYear: 1000,
|
||||
vehicleMake: "CarMake",
|
||||
vehicleModel: "CarModel",
|
||||
vehicleStyle: "SuperCoolStyle",
|
||||
isRepair: false,
|
||||
numberOfChips: 0,
|
||||
carId: "Gibberish",
|
||||
serviceCity: "Columbus",
|
||||
serviceState: "OH-IO",
|
||||
serviceZipCode: 43215,
|
||||
parentAccountNumber: "999999",
|
||||
isCoverageVerified: false,
|
||||
glassParts: [
|
||||
{
|
||||
partNumber: "WINDSHIELDPARTNUMBER",
|
||||
description: "This is a windshield",
|
||||
recalibrationType: "ADAS, maybe",
|
||||
requiresRecalibration: true,
|
||||
requiresCapabilityQuestions: false,
|
||||
childParts: [
|
||||
{
|
||||
partNumber: "THIRD RECAL",
|
||||
description: "Additional Static Recal",
|
||||
recalibrationType:
|
||||
"DUAL & RECAL THIRD & HC FUNCTION TEST & RL SENSOR",
|
||||
ribCode: "RL",
|
||||
safelitePartNumber: "THIRD RECAL",
|
||||
status: "ACTIVE",
|
||||
partType: "ADAS RECALIBRATION",
|
||||
childParts: [],
|
||||
recalibrationFees: [],
|
||||
salesTax: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
otherParts: [],
|
||||
glassToReplace: [
|
||||
{
|
||||
glassLocation: "Windshield",
|
||||
glassName: "Single",
|
||||
},
|
||||
],
|
||||
funnelProviderNumber: "1",
|
||||
funnelReferralType: "CASH QUOTE",
|
||||
funnelServiceZipCodeCtu: "11111",
|
||||
};
|
||||
|
||||
//Act
|
||||
mutations.updateYear(storeState, mockStateValues.vehicleYear);
|
||||
mutations.updateMake(storeState, mockStateValues.vehicleMake);
|
||||
mutations.updateModel(storeState, mockStateValues.vehicleModel);
|
||||
mutations.updateStyle(storeState, mockStateValues.vehicleStyle);
|
||||
mutations.updateIsRepair(storeState, mockStateValues.isRepair);
|
||||
mutations.updateNumberOfChips(storeState, mockStateValues.numberOfChips);
|
||||
mutations.updateCarId(storeState, mockStateValues.carId);
|
||||
mutations.updateServiceLocation(storeState, {
|
||||
city: mockStateValues.serviceCity,
|
||||
state: mockStateValues.serviceState,
|
||||
zipCode: mockStateValues.serviceZipCode,
|
||||
zipCodeCtu: mockStateValues.funnelServiceZipCodeCtu,
|
||||
provider: {
|
||||
providerNumber: mockStateValues.funnelProviderNumber,
|
||||
},
|
||||
});
|
||||
mutations.updateParentAcctNumber(storeState, mockStateValues.parentAccountNumber);
|
||||
mutations.updateInsuranceVerifiedStatus(storeState, mockStateValues.isCoverageVerified);
|
||||
mutations.updateIsInsurance(storeState, false);
|
||||
mutations.updateGlassParts(storeState, mockStateValues.glassParts);
|
||||
mutations.updateSupportingItems(storeState, mockStateValues.funnelSupportingItems);
|
||||
mutations.updateVaps(storeState, mockStateValues.funnelVaps);
|
||||
mutations.updateGlassToReplace(storeState, mockStateValues.glassToReplace);
|
||||
|
||||
//Assert
|
||||
expect(getters.experimentOrder(storeState)).toEqual({
|
||||
funnelVehicleYear: mockStateValues.vehicleYear,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ process.env.VUE_APP_CURRENT_ENVIRONMENT = "Localhost";
|
|||
process.env.VUE_APP_MY_ACCOUNT = "https://myaccountdev.safelite.com/";
|
||||
|
||||
//process.env.VUE_APP_SAFELITE_HOP = "http://localhost:60966/fmgCheckoutShared.aspx";
|
||||
process.env.VUE_APP_SAFELITE_HOP = "https://sv2-safelitehop-sys.safelite.com/fmgCheckoutShared.aspx";
|
||||
process.env.VUE_APP_SAFELITE_HOP = "https://sv2-safelitehop-dev.safelite.com/fmgCheckoutShared.aspx";
|
||||
|
||||
// GA & GTM
|
||||
process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY =
|
||||
|
|
|
|||
Loading…
Reference in a new issue