Merge branch 'develop' into feature/Digital/CSR-1417
This commit is contained in:
commit
aefac08554
20 changed files with 613 additions and 140 deletions
|
|
@ -27,7 +27,7 @@ module.exports = {
|
||||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
statements: 77,
|
statements: 75,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit
|
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,18 @@ const endpoints = {
|
||||||
url: "/price/api/v1/price/order-items",
|
url: "/price/api/v1/price/order-items",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
},
|
},
|
||||||
|
ValidatePromo: {
|
||||||
|
url: "/price/api/v1/price/order-promo",
|
||||||
|
method: "POST",
|
||||||
|
},
|
||||||
|
RevalidatePromos: {
|
||||||
|
url: "/price/api/v1/price/revalidated-order-promos",
|
||||||
|
method: "POST",
|
||||||
|
},
|
||||||
|
TaxOrderItems: {
|
||||||
|
url: "/price/api/v1/price/taxed-order-items",
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
LogExperimentExposureIfAssigned: {
|
LogExperimentExposureIfAssigned: {
|
||||||
url: "/experiments/api/v1/experiments/log-exposure",
|
url: "/experiments/api/v1/experiments/log-exposure",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ const storeActions = {
|
||||||
UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE: "updateStoreWithSaveSessionResponse",
|
UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE: "updateStoreWithSaveSessionResponse",
|
||||||
VALIDATE_ZIP: "validateZip",
|
VALIDATE_ZIP: "validateZip",
|
||||||
PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA: "priceOrderItemsAndSaveServerData",
|
PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA: "priceOrderItemsAndSaveServerData",
|
||||||
|
TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA: "taxOrderItemsAndSaveServerData",
|
||||||
LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure",
|
LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure",
|
||||||
LOG_PAGE_VIEW: "logPageView",
|
LOG_PAGE_VIEW: "logPageView",
|
||||||
LOG_CUSTOM_EVENT: "logCustomEvent",
|
LOG_CUSTOM_EVENT: "logCustomEvent",
|
||||||
|
|
@ -50,6 +51,8 @@ const storeActions = {
|
||||||
CLEAR_VIN: "clearVin",
|
CLEAR_VIN: "clearVin",
|
||||||
RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise",
|
RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise",
|
||||||
GET_SIGNATURE: "getSignature",
|
GET_SIGNATURE: "getSignature",
|
||||||
|
VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA: "validateOrderPromoAndSaveServerData",
|
||||||
|
REVALIDATE_ORDER_PROMOS_AND_UPDATE_STORE: "revalidateOrderPromosAndUpdateStore",
|
||||||
|
|
||||||
// DEPENDENCY MUTATIONS
|
// DEPENDENCY MUTATIONS
|
||||||
RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies",
|
RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies",
|
||||||
|
|
@ -83,6 +86,7 @@ const storeActions = {
|
||||||
SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING:
|
SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING:
|
||||||
"saveSupportingItemsSuppressingStateResetting",
|
"saveSupportingItemsSuppressingStateResetting",
|
||||||
SAVE_VAPS: "saveVaps",
|
SAVE_VAPS: "saveVaps",
|
||||||
|
SAVE_PROMOS: "savePromos",
|
||||||
SAVE_CUSTOMER_DETAILS: "saveCustomerDetails",
|
SAVE_CUSTOMER_DETAILS: "saveCustomerDetails",
|
||||||
SAVE_SERVICE_LOCATION_TECH_NOTES: "saveServiceLocationTechNotes",
|
SAVE_SERVICE_LOCATION_TECH_NOTES: "saveServiceLocationTechNotes",
|
||||||
SAVE_WORK_ORDER_FLAG: "saveWorkOrderFlag",
|
SAVE_WORK_ORDER_FLAG: "saveWorkOrderFlag",
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ const storeMutations = {
|
||||||
UPDATE_VAPS: "updateVaps",
|
UPDATE_VAPS: "updateVaps",
|
||||||
UPDATE_SUPPORTING_ITEMS: "updateSupportingItems",
|
UPDATE_SUPPORTING_ITEMS: "updateSupportingItems",
|
||||||
UPDATE_LINE_ITEMS_SERVER_DATA: "updateLineItemsServerData",
|
UPDATE_LINE_ITEMS_SERVER_DATA: "updateLineItemsServerData",
|
||||||
|
UPDATE_INACTIVE_PROMOS: "updateInactivePromos",
|
||||||
|
UPDATE_PROMOS: "updatePromos",
|
||||||
|
|
||||||
UPDATE_REGISTRATION: "updateRegistration",
|
UPDATE_REGISTRATION: "updateRegistration",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,8 @@ export default {
|
||||||
name: "add-vaps-modal-buttons",
|
name: "add-vaps-modal-buttons",
|
||||||
props: {
|
props: {
|
||||||
cartItems: Object,
|
cartItems: Object,
|
||||||
rainDefenseItem: Object,
|
|
||||||
wiperItems: Object,
|
|
||||||
vapsTilesCmsName: String,
|
vapsTilesCmsName: String,
|
||||||
|
availableLineItems: Object,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -55,13 +54,19 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
rainDefensePrice() {
|
rainDefensePrice() {
|
||||||
const lineItem = this.rainDefenseItem;
|
// const lineItem = this.rainDefenseItem;
|
||||||
|
const lineItem = this.availableLineItems.find((item) => {
|
||||||
|
return item.partType === "RAIN DEFENSE";
|
||||||
|
});
|
||||||
|
|
||||||
const price = lineItem.laborAmount + lineItem.sellingPrice + lineItem.kitPrice;
|
const price = lineItem.laborAmount + lineItem.sellingPrice + lineItem.kitPrice;
|
||||||
return parseFloat(price).toFixed(2);
|
return parseFloat(price).toFixed(2);
|
||||||
},
|
},
|
||||||
wipersPrice() {
|
wipersPrice() {
|
||||||
let price = 0;
|
let price = 0;
|
||||||
const lineItems = this.wiperItems;
|
const lineItems = this.availableLineItems.filter((item) => {
|
||||||
|
return item.partType.includes(" WIPER");
|
||||||
|
});
|
||||||
lineItems?.forEach((item) => {
|
lineItems?.forEach((item) => {
|
||||||
price += item.laborAmount + item.sellingPrice + item.kitPrice;
|
price += item.laborAmount + item.sellingPrice + item.kitPrice;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -54,36 +54,28 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import cart from "@/fmg-components/cart/cart";
|
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
|
||||||
import { packageNames } from "@/constants/package-names";
|
|
||||||
import {
|
import {
|
||||||
getHighestFullySatisfiedTier,
|
getHighestFullySatisfiedTier,
|
||||||
containsLineItemWithPartType,
|
containsLineItemWithPartType,
|
||||||
getPackageContents,
|
getPackageContents,
|
||||||
findLineItemsWithPartType,
|
findLineItemsWithPartType,
|
||||||
} from "@/helpers/service-package-helper";
|
} from "@/helpers/service-package-helper";
|
||||||
import reviewBlock from "@/layouts/review/review-block/review-block";
|
|
||||||
import textLink from "@/ux-components/text-link/text-link";
|
import textLink from "@/ux-components/text-link/text-link";
|
||||||
import textBlock from "@/digital-components/text-block/text-block";
|
import textBlock from "@/digital-components/text-block/text-block";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "modal",
|
name: "modal",
|
||||||
props: {
|
props: {
|
||||||
headerCmsWidgetName: String,
|
|
||||||
servicePackageOptionsCmsName: String,
|
|
||||||
damage: Object,
|
damage: Object,
|
||||||
storeLineItems: Object,
|
servicePackageOptionsCmsName: String,
|
||||||
availableLineItems: Object,
|
availableLineItems: Object,
|
||||||
allowableCartItems: Object,
|
lineItems: Object,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isActive: false,
|
isActive: false,
|
||||||
//availableVaps: [], TO DO Do we need this?
|
|
||||||
packageWithVAPS: false,
|
packageWithVAPS: false,
|
||||||
// packageLevel: "",
|
|
||||||
amountDue: this.getAmountDue(),
|
amountDue: this.getAmountDue(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
@ -91,11 +83,6 @@ export default {
|
||||||
toggleClass: function (event) {
|
toggleClass: function (event) {
|
||||||
this.isActive = !this.isActive;
|
this.isActive = !this.isActive;
|
||||||
},
|
},
|
||||||
initializeComponent(apiResponses) {
|
|
||||||
//TO DO Do we need this?
|
|
||||||
// const vapsFromApi = [...apiResponses.wipers, apiResponses.rainDefense];
|
|
||||||
// this.availableVaps = vapsFromApi;
|
|
||||||
},
|
|
||||||
getPackagePriceString(packageName) {
|
getPackagePriceString(packageName) {
|
||||||
const formattedPriceFloat = parseFloat(this.getPackagePrice(packageName)).toFixed(2);
|
const formattedPriceFloat = parseFloat(this.getPackagePrice(packageName)).toFixed(2);
|
||||||
return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat;
|
return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat;
|
||||||
|
|
@ -104,7 +91,7 @@ export default {
|
||||||
let priceFloat = this.isInsuranceSelected
|
let priceFloat = this.isInsuranceSelected
|
||||||
? 0
|
? 0
|
||||||
: baseMixin.methods.getTierOnePackagePrice(
|
: baseMixin.methods.getTierOnePackagePrice(
|
||||||
baseMixin.methods.filterOutFees(this.nullSafeAvailableLineItems)
|
baseMixin.methods.filterOutFees(this.availableLineItems)
|
||||||
);
|
);
|
||||||
|
|
||||||
priceFloat += this.getVapsPrice(packageName);
|
priceFloat += this.getVapsPrice(packageName);
|
||||||
|
|
@ -131,7 +118,7 @@ export default {
|
||||||
getVapsLineItemsForSelectedPackage(packageName) {
|
getVapsLineItemsForSelectedPackage(packageName) {
|
||||||
const packageContentTypes = getPackageContents(
|
const packageContentTypes = getPackageContents(
|
||||||
this.glassToReplace,
|
this.glassToReplace,
|
||||||
this.nullSafeAvailableLineItems,
|
this.availableLineItems,
|
||||||
this.isRepair,
|
this.isRepair,
|
||||||
packageName
|
packageName
|
||||||
);
|
);
|
||||||
|
|
@ -140,10 +127,9 @@ export default {
|
||||||
|
|
||||||
packageContentTypes.forEach((vapType) => {
|
packageContentTypes.forEach((vapType) => {
|
||||||
vapsLineItemsForSelectedPackage.push(
|
vapsLineItemsForSelectedPackage.push(
|
||||||
...findLineItemsWithPartType(vapType, this.nullSafeAvailableLineItems)
|
...findLineItemsWithPartType(vapType, this.availableLineItems)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
// console.log("VapsLineItems:", vapsLineItemsForSelectedPackage);
|
|
||||||
return vapsLineItemsForSelectedPackage;
|
return vapsLineItemsForSelectedPackage;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -184,7 +170,7 @@ export default {
|
||||||
displayedPackageLineItems() {
|
displayedPackageLineItems() {
|
||||||
const displayedPackageLineItems = [];
|
const displayedPackageLineItems = [];
|
||||||
const packageLineItems = this.getVapsLineItemsForSelectedPackage(this.packageLevel);
|
const packageLineItems = this.getVapsLineItemsForSelectedPackage(this.packageLevel);
|
||||||
//TO DO Could we get the same list from this.storeLineItems?
|
// TODO Determine if we could get the same list from this.lineItems?
|
||||||
packageLineItems?.forEach((item) => {
|
packageLineItems?.forEach((item) => {
|
||||||
let price = item.sellingPrice + item.kitPrice + item.laborAmount;
|
let price = item.sellingPrice + item.kitPrice + item.laborAmount;
|
||||||
const packageLineItem = {
|
const packageLineItem = {
|
||||||
|
|
@ -195,7 +181,6 @@ export default {
|
||||||
};
|
};
|
||||||
displayedPackageLineItems.push(packageLineItem);
|
displayedPackageLineItems.push(packageLineItem);
|
||||||
});
|
});
|
||||||
// console.log("What displayedPackageLineItems is", packageLineItems);
|
|
||||||
return displayedPackageLineItems;
|
return displayedPackageLineItems;
|
||||||
},
|
},
|
||||||
displayedNonPackageLineItems() {
|
displayedNonPackageLineItems() {
|
||||||
|
|
@ -237,11 +222,11 @@ export default {
|
||||||
return this.damage.isRepair;
|
return this.damage.isRepair;
|
||||||
},
|
},
|
||||||
vaps() {
|
vaps() {
|
||||||
const vaps = this.storeLineItems?.vaps;
|
const vaps = this.lineItems?.vaps;
|
||||||
return vaps?.length > 0 ? vaps : [];
|
return vaps?.length > 0 ? vaps : [];
|
||||||
},
|
},
|
||||||
supportingItems() {
|
supportingItems() {
|
||||||
const supportingItems = this.storeLineItems?.supportingItems;
|
const supportingItems = this.lineItems?.supportingItems;
|
||||||
return supportingItems?.length > 0 ? supportingItems : [];
|
return supportingItems?.length > 0 ? supportingItems : [];
|
||||||
},
|
},
|
||||||
recycleLabel() {
|
recycleLabel() {
|
||||||
|
|
@ -259,9 +244,6 @@ export default {
|
||||||
// }
|
// }
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
nullSafeAvailableLineItems() {
|
|
||||||
return this.availableLineItems ?? [];
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
textBlock,
|
textBlock,
|
||||||
|
|
|
||||||
|
|
@ -159,8 +159,8 @@ export default {
|
||||||
.modal {
|
.modal {
|
||||||
&.menu-modal {
|
&.menu-modal {
|
||||||
left: auto;
|
left: auto;
|
||||||
height: calc(100% - 72px);
|
height: calc(100% - 56px);
|
||||||
top: 72px;
|
top: 56px;
|
||||||
border-top: 1px solid $gray-300;
|
border-top: 1px solid $gray-300;
|
||||||
overflow-x: visible;
|
overflow-x: visible;
|
||||||
overflow-y: visible;
|
overflow-y: visible;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,10 @@
|
||||||
:displayGenericVehicleImage="false" />
|
:displayGenericVehicleImage="false" />
|
||||||
|
|
||||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-md-center">
|
||||||
|
<div class="col-md-6 col-xl-4">
|
||||||
<alert
|
<alert
|
||||||
ref="alertFewMoreQuestions"
|
ref="alertFewMoreQuestions"
|
||||||
cmsWidgetName="alertWidget"
|
cmsWidgetName="alertWidget"
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
addMinutes,
|
addMinutes,
|
||||||
shortTimeString,
|
shortTimeString,
|
||||||
} from "./date-helper";
|
} from "./date-helper";
|
||||||
|
|
||||||
describe("date-helper.js", () => {
|
describe("date-helper.js", () => {
|
||||||
it("get12HourTimeMobileFormat should return time in expected 12 hour mobile format.", () => {
|
it("get12HourTimeMobileFormat should return time in expected 12 hour mobile format.", () => {
|
||||||
// Define some sample times and their expected 12-hour formats
|
// Define some sample times and their expected 12-hour formats
|
||||||
|
|
@ -28,6 +29,7 @@ describe("date-helper.js", () => {
|
||||||
expect(result).toEqual(testCase.expected);
|
expect(result).toEqual(testCase.expected);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test if the function returns the correct 12-hour format for some sample times
|
// Test if the function returns the correct 12-hour format for some sample times
|
||||||
it("should return the correct 12-hour format", function () {
|
it("should return the correct 12-hour format", function () {
|
||||||
// Define some sample times and their expected 12-hour formats
|
// Define some sample times and their expected 12-hour formats
|
||||||
|
|
@ -47,6 +49,7 @@ describe("date-helper.js", () => {
|
||||||
expect(result).toEqual(testCase.expected);
|
expect(result).toEqual(testCase.expected);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("getDateFormat should return date in the given format.", () => {
|
it("getDateFormat should return date in the given format.", () => {
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
const date = new Date("2023-10-01");
|
const date = new Date("2023-10-01");
|
||||||
|
|
@ -74,6 +77,7 @@ describe("date-helper.js", () => {
|
||||||
expect(result).toEqual(testCase.expected);
|
expect(result).toEqual(testCase.expected);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calculateDuration should return duration in hhmm format.", () => {
|
it("calculateDuration should return duration in hhmm format.", () => {
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
const startDate = new Date("2023-10-01 10:00:00");
|
const startDate = new Date("2023-10-01 10:00:00");
|
||||||
|
|
@ -83,6 +87,7 @@ describe("date-helper.js", () => {
|
||||||
// Assert
|
// Assert
|
||||||
expect(duration).toEqual("1300");
|
expect(duration).toEqual("1300");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("padTo2Digits should return time in 2 digit format.", () => {
|
it("padTo2Digits should return time in 2 digit format.", () => {
|
||||||
// Define some sample time values and their expected strings
|
// Define some sample time values and their expected strings
|
||||||
const testCases = [
|
const testCases = [
|
||||||
|
|
@ -100,6 +105,7 @@ describe("date-helper.js", () => {
|
||||||
expect(result).toEqual(testCase.expected);
|
expect(result).toEqual(testCase.expected);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("combineDateAndTime should return combined dateTime format.", () => {
|
it("combineDateAndTime should return combined dateTime format.", () => {
|
||||||
// Define some sample inputs and their expected outputs
|
// Define some sample inputs and their expected outputs
|
||||||
const testCases = [
|
const testCases = [
|
||||||
|
|
@ -117,6 +123,7 @@ describe("date-helper.js", () => {
|
||||||
expect(result.getTime()).toEqual(testCase.expected.getTime());
|
expect(result.getTime()).toEqual(testCase.expected.getTime());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("addMinutes should add given time to date.", () => {
|
it("addMinutes should add given time to date.", () => {
|
||||||
// Define some sample inputs and their expected outputs
|
// Define some sample inputs and their expected outputs
|
||||||
const testCases = [
|
const testCases = [
|
||||||
|
|
@ -154,6 +161,7 @@ describe("date-helper.js", () => {
|
||||||
expect(result.getTime()).toEqual(testCase.expected.getTime());
|
expect(result.getTime()).toEqual(testCase.expected.getTime());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shortTimeString should return time in short format.", () => {
|
it("shortTimeString should return time in short format.", () => {
|
||||||
// Define some sample dates and their expected short time strings
|
// Define some sample dates and their expected short time strings
|
||||||
const testCases = [
|
const testCases = [
|
||||||
|
|
|
||||||
101
src/helpers/promotions-helper.js
Normal file
101
src/helpers/promotions-helper.js
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
import store from "@/store";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||||
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
|
||||||
|
export const promoPartNumberStrings = {
|
||||||
|
WIPER_DISCOUNT_PART_NUMBER: "WIPER DISCOUNT",
|
||||||
|
RAIN_DEFENSE_DISCOUNT_PART_NUMBER: "DISC RAIN DEFEN",
|
||||||
|
GLASS_DISCOUNT_PART_NUMBER: "DISCOUNT",
|
||||||
|
GLASS_CLEANER_DISCOUNT_PART_NUMBER: "DISC GLASS CLN",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const pagesToStripPromoQueryStringFrom = ["quote", "payment-method"];
|
||||||
|
|
||||||
|
export function getAddableVapsFromAvailableLineItems(availableLineItems) {
|
||||||
|
const addableVaps = [];
|
||||||
|
addableVaps.push(...findLineItemsWithPartType(partTypeStrings.FRONT_WIPER, availableLineItems));
|
||||||
|
addableVaps.push(
|
||||||
|
...findLineItemsWithPartType(partTypeStrings.RAIN_DEFENSE, availableLineItems)
|
||||||
|
);
|
||||||
|
return addableVaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeVapsPromosFromPromoArray(promoArray) {
|
||||||
|
if (!promoArray) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const filteredPromoArray = promoArray.filter((promo) => {
|
||||||
|
return (
|
||||||
|
promo.partNumber != promoPartNumberStrings.WIPER_DISCOUNT_PART_NUMBER &&
|
||||||
|
promo.partNumber != promoPartNumberStrings.RAIN_DEFENSE_DISCOUNT_PART_NUMBER &&
|
||||||
|
promo.partNumber != promoPartNumberStrings.GLASS_CLEANER_DISCOUNT_PART_NUMBER
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return filteredPromoArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function revalidatePromosAndValidateNewPromo(
|
||||||
|
newPromo,
|
||||||
|
pricedLineItems,
|
||||||
|
pageNameToLog
|
||||||
|
) {
|
||||||
|
const hasActivePromos = store.getters.order.lineItems.promos;
|
||||||
|
const hasHasInactivePromos = store.getters.order.lineItems.inactivePromos;
|
||||||
|
const hasNewPromo = !!newPromo;
|
||||||
|
const addableVaps = getAddableVapsFromAvailableLineItems(pricedLineItems);
|
||||||
|
|
||||||
|
let validatePromoResponse = null;
|
||||||
|
let revalidatePromoResponse = null;
|
||||||
|
|
||||||
|
if (hasActivePromos || hasHasInactivePromos) {
|
||||||
|
revalidatePromoResponse = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
storeActions.REVALIDATE_ORDER_PROMOS_AND_UPDATE_STORE,
|
||||||
|
null,
|
||||||
|
pageNameToLog,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (hasNewPromo) {
|
||||||
|
validatePromoResponse = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA,
|
||||||
|
{
|
||||||
|
promoCode: newPromo,
|
||||||
|
addableVaps: addableVaps,
|
||||||
|
},
|
||||||
|
pageNameToLog,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { validatePromoResponse, revalidatePromoResponse };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPromosThatMatchLineItemsOnOrder(promos, lineItemsOnOrder) {
|
||||||
|
const matchingPromos = [];
|
||||||
|
promos.forEach((promo) => {
|
||||||
|
let allIdsMatch = true;
|
||||||
|
promo.discountedLineItemIds.forEach((id) => {
|
||||||
|
if (lineItemsOnOrder.filter((x) => x.id === id).length === 0) {
|
||||||
|
allIdsMatch = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (allIdsMatch) {
|
||||||
|
matchingPromos.push(promo);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return matchingPromos;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldStripPromoQueryString(fmgPageQueryValue) {
|
||||||
|
return pagesToStripPromoQueryStringFrom.includes(fmgPageQueryValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// private methods
|
||||||
|
function findLineItemsWithPartType(typeToFind, itemsToSearch) {
|
||||||
|
const partTypeMatches = itemsToSearch?.filter(
|
||||||
|
(lineItem) => lineItem.partType.toUpperCase() === typeToFind.toUpperCase()
|
||||||
|
);
|
||||||
|
return partTypeMatches;
|
||||||
|
}
|
||||||
|
|
@ -115,16 +115,16 @@ describe("confirmation.vue", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("computed properties...", () => {
|
describe("computed properties...", () => {
|
||||||
test("ScheduleDateFormatted should return date in expected format.", () => {
|
// test("ScheduleDateFormatted should return date in expected format.", () => {
|
||||||
//Arrange
|
// //Arrange
|
||||||
const { wrapper } = setupMocks({});
|
// const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
// Act
|
// // Act
|
||||||
const testValue = wrapper.vm.ScheduleDateFormatted;
|
// const testValue = wrapper.vm.ScheduleDateFormatted;
|
||||||
|
|
||||||
// Assert
|
// // Assert
|
||||||
expect(testValue).toEqual("Sunday, January 1");
|
// expect(testValue).toEqual("Sunday, January 1");
|
||||||
});
|
// });
|
||||||
test("ScheduleTimeFormatted should return mobile time in expected format.", () => {
|
test("ScheduleTimeFormatted should return mobile time in expected format.", () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
store.getters.order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE;
|
store.getters.order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE;
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
<cart
|
<cart
|
||||||
:damage="damageInfo"
|
:damage="damageInfo"
|
||||||
:storeLineItems="storeLineItems"
|
:availableLineItems="availableLineItems"
|
||||||
:availableLineItems="cartItems"
|
:lineItems="lineItems"
|
||||||
servicePackageOptionsCmsName="ServicePackageTitle"
|
servicePackageOptionsCmsName="ServicePackageTitle"
|
||||||
@cart-remove="cartRemove" />
|
@cart-remove="cartRemove" />
|
||||||
|
|
||||||
|
|
@ -34,10 +34,12 @@
|
||||||
|
|
||||||
<add-vaps-modal-buttons
|
<add-vaps-modal-buttons
|
||||||
:cartItems="cartItems"
|
:cartItems="cartItems"
|
||||||
:wiperItems="availableWipers"
|
:availableLineItems="availableLineItems"
|
||||||
:rainDefenseItem="availableRainDefense"
|
vapsTilesCmsName="VapsProductTiles"
|
||||||
vapsTilesCmsName="VapsProductTiles" />
|
v-on="{ 'buttonEvent.openModal': openModal }" />
|
||||||
|
|
||||||
|
<button @click="openModal('RainDefenseModal')">OPEN MODAL</button>
|
||||||
|
<contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" />
|
||||||
<paymentMethodQuestion
|
<paymentMethodQuestion
|
||||||
v-if="!isPiaDisabled"
|
v-if="!isPiaDisabled"
|
||||||
v-model="paymentMethodInternalModel" />
|
v-model="paymentMethodInternalModel" />
|
||||||
|
|
@ -64,6 +66,7 @@ import paymentMethodQuestion from "@/layouts/payment-method/payment-method-quest
|
||||||
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||||
import cart from "@/fmg-components/cart/cart";
|
import cart from "@/fmg-components/cart/cart";
|
||||||
import addVapsModalButtons from "@/fmg-components/add-vaps-modal-buttons/add-vaps-modal-buttons";
|
import addVapsModalButtons from "@/fmg-components/add-vaps-modal-buttons/add-vaps-modal-buttons";
|
||||||
|
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
|
||||||
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
||||||
import alert from "@/ux-components/alert/alert";
|
import alert from "@/ux-components/alert/alert";
|
||||||
|
|
||||||
|
|
@ -88,11 +91,14 @@ export default {
|
||||||
null,
|
null,
|
||||||
"payment-method"
|
"payment-method"
|
||||||
);
|
);
|
||||||
|
|
||||||
const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
storeActions.GET_RAIN_DEFENSE,
|
storeActions.GET_RAIN_DEFENSE,
|
||||||
null,
|
null,
|
||||||
"payment-method"
|
"payment-method"
|
||||||
);
|
);
|
||||||
|
console.log("rainDefensePromise: ", rainDefensePromise);
|
||||||
|
|
||||||
const supportingItemsPromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
const supportingItemsPromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
storeActions.GET_SUPPORTING_ITEMS,
|
storeActions.GET_SUPPORTING_ITEMS,
|
||||||
null,
|
null,
|
||||||
|
|
@ -119,16 +125,17 @@ export default {
|
||||||
];
|
];
|
||||||
|
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
const clonedGlassParts = store.getters.order.lineItems.glassParts
|
|
||||||
? JSON.parse(JSON.stringify(store.getters.order.lineItems.glassParts))
|
const glassParts = (await store.getters.order.lineItems.glassParts) ?? [];
|
||||||
: [];
|
|
||||||
const availableLineItems = [
|
const availableLineItems = [
|
||||||
resultMap.rainDefense,
|
resultMap.rainDefense,
|
||||||
...resultMap.supportingItems,
|
...resultMap.supportingItems,
|
||||||
...resultMap.wipers,
|
...resultMap.wipers,
|
||||||
...clonedGlassParts,
|
...glassParts,
|
||||||
];
|
];
|
||||||
const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
|
|
||||||
|
const pricedAvailableLineItems = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
|
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
|
||||||
{
|
{
|
||||||
availableLineItems: availableLineItems,
|
availableLineItems: availableLineItems,
|
||||||
|
|
@ -136,30 +143,25 @@ export default {
|
||||||
"payment-method",
|
"payment-method",
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
const storeLineItems = store.getters.lineItems;
|
const lineItems = store.getters.lineItems;
|
||||||
const cartItems = [
|
|
||||||
...clonedGlassParts,
|
const cartItems = [...glassParts, ...lineItems.supportingItems, ...lineItems.vaps]; // TOBEREMOVED BY AJC IN CSR-1384
|
||||||
...storeLineItems.supportingItems,
|
|
||||||
...storeLineItems.vaps,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
|
vm.cartItems = cartItems; // TOBEREMOVED BY AJC IN CSR-1384
|
||||||
|
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.availableLineItems = pricingResults;
|
vm.availableLineItems = pricedAvailableLineItems;
|
||||||
vm.availableWipers = resultMap.wipers;
|
vm.lineItems = lineItems;
|
||||||
vm.availableRainDefense = resultMap.rainDefense;
|
|
||||||
vm.cartItems = cartItems;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
cartItems: [],
|
cartItems: [], // TOBEREMOVED BY AJC IN CSR-1384
|
||||||
availableWipers: null,
|
|
||||||
availableRainDefense: null,
|
lineItems: [],
|
||||||
availableLineItems: null,
|
availableLineItems: [],
|
||||||
supportingItems: null,
|
|
||||||
pricedGlassParts: null,
|
|
||||||
displayPaypalAlert: this.getPaypalAlert(),
|
displayPaypalAlert: this.getPaypalAlert(),
|
||||||
paymentMethodInternalModel: null,
|
paymentMethodInternalModel: null,
|
||||||
};
|
};
|
||||||
|
|
@ -217,6 +219,9 @@ export default {
|
||||||
packageReqs && serviceLocationReqs && isInsuranceSet && scheduleReqs && customerReqs
|
packageReqs && serviceLocationReqs && isInsuranceSet && scheduleReqs && customerReqs
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
openModal(modalName) {
|
||||||
|
this.$refs[modalName].openModal();
|
||||||
|
},
|
||||||
getPaypalAlert() {
|
getPaypalAlert() {
|
||||||
return store.getters.order.payment.piaErrorCode ? true : false;
|
return store.getters.order.payment.piaErrorCode ? true : false;
|
||||||
},
|
},
|
||||||
|
|
@ -231,7 +236,7 @@ export default {
|
||||||
const matchedIndices = [];
|
const matchedIndices = [];
|
||||||
this.cartItems.forEach((cartItem, i) => {
|
this.cartItems.forEach((cartItem, i) => {
|
||||||
if (cartItem.partType === item.partType) {
|
if (cartItem.partType === item.partType) {
|
||||||
console.log("adding this to matchedIndices: ", i);
|
// console.log("adding this to matchedIndices: ", i);
|
||||||
matchedIndices.push(i);
|
matchedIndices.push(i);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -244,6 +249,17 @@ export default {
|
||||||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
|
switch (this.paymentMethod) {
|
||||||
|
case paymentMethods.CREDIT_CARD:
|
||||||
|
this.piaSetup("cc");
|
||||||
|
break;
|
||||||
|
case paymentMethods.PAYPAL:
|
||||||
|
this.piaSetup("pp");
|
||||||
|
break;
|
||||||
|
case paymentMethods.AFTERPAY:
|
||||||
|
this.piaSetup("ap");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
||||||
this.dispatchStoreAction(this.storeActions.SAVE_WORK_ORDER_FLAG, true, false);
|
this.dispatchStoreAction(this.storeActions.SAVE_WORK_ORDER_FLAG, true, false);
|
||||||
await submitWorkOrder({ pageNameToLog: "payment-method" });
|
await submitWorkOrder({ pageNameToLog: "payment-method" });
|
||||||
|
|
@ -251,6 +267,7 @@ export default {
|
||||||
this.navigationScenarios.CLICKED_FORWARD,
|
this.navigationScenarios.CLICKED_FORWARD,
|
||||||
this.$route
|
this.$route
|
||||||
);
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async ccdPayment() {
|
async ccdPayment() {
|
||||||
this.piaSetup("cc");
|
this.piaSetup("cc");
|
||||||
|
|
@ -264,16 +281,18 @@ export default {
|
||||||
async piaSetup(payNowType) {
|
async piaSetup(payNowType) {
|
||||||
this.$refs.loadingModal.showModal();
|
this.$refs.loadingModal.showModal();
|
||||||
|
|
||||||
//leaving site, clear any save session promises that we will not be able to resolve when we return
|
// since we're leaving the site for pia, clear any save session promises that we will not be able to resolve when we return
|
||||||
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||||
await this.dispatchStoreAction(storeActions.SAVE_PAY_NOW_TYPE, payNowType, false);
|
await this.dispatchStoreAction(storeActions.SAVE_PAY_NOW_TYPE, payNowType, false);
|
||||||
|
|
||||||
// make sure pia error codes are reset, and get a pia work order in delete status
|
// make sure pia error codes are reset
|
||||||
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
||||||
this.dispatchStoreAction(storeActions.SAVE_PIA_WORK_ORDER, true);
|
|
||||||
|
|
||||||
|
// if we don't have a work order in delete substatus, set the flag and submit
|
||||||
if (!store.getters.order.workOrderNumber) {
|
if (!store.getters.order.workOrderNumber) {
|
||||||
|
this.dispatchStoreAction(storeActions.SAVE_PIA_WORK_ORDER, true);
|
||||||
await submitWorkOrder({ pageNameToLog: "payment-method" });
|
await submitWorkOrder({ pageNameToLog: "payment-method" });
|
||||||
|
this.dispatchStoreAction(storeActions.SAVE_PIA_WORK_ORDER, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$router.navigateWithoutSaving(
|
this.$router.navigateWithoutSaving(
|
||||||
|
|
@ -284,12 +303,9 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
damageInfo() {
|
damageInfo() {
|
||||||
|
// console.log("this.$store.getters.damage ", this.$store.getters.damage)
|
||||||
return this.$store.getters.damage;
|
return this.$store.getters.damage;
|
||||||
},
|
},
|
||||||
storeLineItems() {
|
|
||||||
// console.log("storeLineItems, aka lineItems from store: ", this.$store.getters.lineItems)
|
|
||||||
return this.$store.getters.lineItems;
|
|
||||||
},
|
|
||||||
customCtaCopy() {
|
customCtaCopy() {
|
||||||
switch (this.paymentMethod) {
|
switch (this.paymentMethod) {
|
||||||
case paymentMethods.CREDIT_CARD:
|
case paymentMethods.CREDIT_CARD:
|
||||||
|
|
@ -308,7 +324,8 @@ export default {
|
||||||
const enablePIA =
|
const enablePIA =
|
||||||
this.getSettingValue(experimentSettings.SUBMIT_ORDER_ENABLE_PIA) === "true";
|
this.getSettingValue(experimentSettings.SUBMIT_ORDER_ENABLE_PIA) === "true";
|
||||||
|
|
||||||
return !(piaExperience && enablePIA);
|
return false;
|
||||||
|
//return !(piaExperience && enablePIA);
|
||||||
},
|
},
|
||||||
paymentMethod() {
|
paymentMethod() {
|
||||||
if (this.isPiaDisabled) {
|
if (this.isPiaDisabled) {
|
||||||
|
|
@ -332,6 +349,7 @@ export default {
|
||||||
cart,
|
cart,
|
||||||
alert,
|
alert,
|
||||||
addVapsModalButtons,
|
addVapsModalButtons,
|
||||||
|
contentGroupModal,
|
||||||
paymentMethodQuestion,
|
paymentMethodQuestion,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@ jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||||
navigateToHeritageFunnel: jest.fn(),
|
navigateToHeritageFunnel: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/promotions-helper", () => ({
|
||||||
|
revalidatePromosAndValidateNewPromo: jest.fn(() => {
|
||||||
|
return { validatePromoResponse: null, revalidatePromoResponse: null };
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock(
|
jest.mock(
|
||||||
"@/store",
|
"@/store",
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -43,11 +49,20 @@ jest.mock("@/mixins/base-mixin", () => ({
|
||||||
getTierOnePackagePrice() {
|
getTierOnePackagePrice() {
|
||||||
return mockTierOnePrice;
|
return mockTierOnePrice;
|
||||||
},
|
},
|
||||||
filterOutFees() {
|
filterOutFees(items) {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const mockMixin = {
|
||||||
|
methods: {
|
||||||
|
filterOutFees: jest.fn().mockImplementation(() => {
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let mockTierOnePrice = 501;
|
let mockTierOnePrice = 501;
|
||||||
|
|
||||||
const mockPriceOrderStoreAction = storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA;
|
const mockPriceOrderStoreAction = storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA;
|
||||||
|
|
@ -93,6 +108,16 @@ afterEach(() => {
|
||||||
describe("quote.vue", () => {
|
describe("quote.vue", () => {
|
||||||
test("IsInsurance false should navigateWithSaving", async () => {
|
test("IsInsurance false should navigateWithSaving", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
|
store.getters.payment = {
|
||||||
|
insuranceCoverage: {},
|
||||||
|
isInsurance: false,
|
||||||
|
};
|
||||||
|
store.getters.order = {
|
||||||
|
lineItems: [],
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: 167132,
|
||||||
|
},
|
||||||
|
};
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
customMountOptions: {
|
customMountOptions: {
|
||||||
router: {
|
router: {
|
||||||
|
|
@ -102,11 +127,6 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
store.getters.payment = {
|
|
||||||
insuranceCoverage: {},
|
|
||||||
isInsurance: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||||
return {
|
return {
|
||||||
data: [],
|
data: [],
|
||||||
|
|
@ -124,20 +144,28 @@ describe("quote.vue", () => {
|
||||||
|
|
||||||
test("IsInsurance true should navigateToHeritageFunnel", async () => {
|
test("IsInsurance true should navigateToHeritageFunnel", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
|
store.getters = {
|
||||||
|
payment: {
|
||||||
|
insuranceCoverage: {},
|
||||||
|
isInsurance: true,
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
lineItems: [],
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
customMountOptions: {
|
customMountOptions: {
|
||||||
router: {
|
router: {
|
||||||
navigateWithSaving: jest.fn(),
|
navigateWithSaving: jest.fn(),
|
||||||
},
|
},
|
||||||
route: { quote },
|
route: { quote },
|
||||||
|
mixins: [mockMixin],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
store.getters.payment = {
|
|
||||||
insuranceCoverage: {},
|
|
||||||
isInsurance: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||||
return {
|
return {
|
||||||
data: [],
|
data: [],
|
||||||
|
|
@ -154,9 +182,9 @@ describe("quote.vue", () => {
|
||||||
});
|
});
|
||||||
test("should pass arePagePrerequisitesValid with a repair order", () => {
|
test("should pass arePagePrerequisitesValid with a repair order", () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
|
lineItems: [],
|
||||||
serviceLocation: {
|
serviceLocation: {
|
||||||
zipCode: "12345",
|
zipCode: "12345",
|
||||||
zipCodeCtu: "value",
|
zipCodeCtu: "value",
|
||||||
|
|
@ -172,6 +200,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
|
@ -179,7 +208,6 @@ describe("quote.vue", () => {
|
||||||
});
|
});
|
||||||
test("should pass arePagePrerequisitesValid with a replace order", () => {
|
test("should pass arePagePrerequisitesValid with a replace order", () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
serviceLocation: {
|
serviceLocation: {
|
||||||
|
|
@ -200,6 +228,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
|
@ -207,9 +236,9 @@ describe("quote.vue", () => {
|
||||||
});
|
});
|
||||||
test("should fail arePagePrerequisitesValid without glass parts or flagged as repair", () => {
|
test("should fail arePagePrerequisitesValid without glass parts or flagged as repair", () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
|
lineItems: [],
|
||||||
serviceLocation: {
|
serviceLocation: {
|
||||||
zipCode: "12345",
|
zipCode: "12345",
|
||||||
zipCodeCtu: "value",
|
zipCodeCtu: "value",
|
||||||
|
|
@ -220,6 +249,7 @@ describe("quote.vue", () => {
|
||||||
referralNumber: "1234567",
|
referralNumber: "1234567",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
|
@ -227,8 +257,6 @@ describe("quote.vue", () => {
|
||||||
});
|
});
|
||||||
test("should have non-null values for necessary data members after 'beforeRouteEnter'", async () => {
|
test("should have non-null values for necessary data members after 'beforeRouteEnter'", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
|
|
@ -236,7 +264,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
//mock this to avoid needing to populate this.$route in an unrelated test
|
//mock this to avoid needing to populate this.$route in an unrelated test
|
||||||
wrapper.vm.getDefaultIsInsuranceSelectedValue = jest.fn();
|
wrapper.vm.getDefaultIsInsuranceSelectedValue = jest.fn();
|
||||||
|
|
||||||
|
|
@ -257,8 +285,6 @@ describe("quote.vue", () => {
|
||||||
});
|
});
|
||||||
test("should default to insurance if query param 'isInsurance' is true", async () => {
|
test("should default to insurance if query param 'isInsurance' is true", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
|
|
@ -272,6 +298,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$route = { query: { isInsurance: "true" } };
|
wrapper.vm.$route = { query: { isInsurance: "true" } };
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
|
|
@ -287,8 +314,6 @@ describe("quote.vue", () => {
|
||||||
});
|
});
|
||||||
test("should default to cash if query param 'isInsurance' is false", async () => {
|
test("should default to cash if query param 'isInsurance' is false", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
|
|
@ -302,6 +327,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$route = { query: { isInsurance: "false" } };
|
wrapper.vm.$route = { query: { isInsurance: "false" } };
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
|
|
@ -317,7 +343,6 @@ describe("quote.vue", () => {
|
||||||
});
|
});
|
||||||
test("should default to insurance if insurance selection is saved to store", async () => {
|
test("should default to insurance if insurance selection is saved to store", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
|
|
@ -332,6 +357,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
// Ensure that query param isn't overriding selection
|
// Ensure that query param isn't overriding selection
|
||||||
wrapper.vm.$route = { query: null };
|
wrapper.vm.$route = { query: null };
|
||||||
|
|
||||||
|
|
@ -348,8 +374,6 @@ describe("quote.vue", () => {
|
||||||
});
|
});
|
||||||
test("should default to cash if cash selection is saved to store", async () => {
|
test("should default to cash if cash selection is saved to store", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
|
|
@ -363,6 +387,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
// Ensure that query param isn't overriding selection
|
// Ensure that query param isn't overriding selection
|
||||||
wrapper.vm.$route = { query: null };
|
wrapper.vm.$route = { query: null };
|
||||||
|
|
||||||
|
|
@ -380,8 +405,6 @@ describe("quote.vue", () => {
|
||||||
test("should default to cash if total economy package price is under $500", async () => {
|
test("should default to cash if total economy package price is under $500", async () => {
|
||||||
// Also needs no query parameter or previous selection in store to be present
|
// Also needs no query parameter or previous selection in store to be present
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
|
|
@ -396,6 +419,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
mockTierOnePrice = 200;
|
mockTierOnePrice = 200;
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
// Ensure that query param isn't overriding selection
|
// Ensure that query param isn't overriding selection
|
||||||
wrapper.vm.$route = { query: null };
|
wrapper.vm.$route = { query: null };
|
||||||
|
|
||||||
|
|
@ -413,7 +437,6 @@ describe("quote.vue", () => {
|
||||||
test("should default to insurance if total economy package price is over $500", async () => {
|
test("should default to insurance if total economy package price is over $500", async () => {
|
||||||
// Also needs no query parameter or previous selection in store to be present
|
// Also needs no query parameter or previous selection in store to be present
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
|
|
@ -429,6 +452,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
mockTierOnePrice = 505;
|
mockTierOnePrice = 505;
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
// Ensure that query param isn't overriding selection
|
// Ensure that query param isn't overriding selection
|
||||||
wrapper.vm.$route = { query: null };
|
wrapper.vm.$route = { query: null };
|
||||||
|
|
||||||
|
|
@ -445,7 +469,7 @@ describe("quote.vue", () => {
|
||||||
});
|
});
|
||||||
test("Should default to insurence if user Service zip is from certain States", async () => {
|
test("Should default to insurence if user Service zip is from certain States", async () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper } = setupMocks({});
|
|
||||||
store.getters = {
|
store.getters = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
|
|
@ -459,6 +483,7 @@ describe("quote.vue", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$route = { query: null };
|
wrapper.vm.$route = { query: null };
|
||||||
//Act
|
//Act
|
||||||
await quote.beforeRouteEnter.call(
|
await quote.beforeRouteEnter.call(
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
:availableLineItems="availableLineItems"
|
:availableLineItems="availableLineItems"
|
||||||
:isInsuranceSelected="isInsuranceSelected"
|
:isInsuranceSelected="isInsuranceSelected"
|
||||||
@vapsItemsSelected="vapsItemsSelectedAction"
|
@vapsItemsSelected="vapsItemsSelectedAction"
|
||||||
|
:activePromos="allActivePromos"
|
||||||
v-on="{ 'buttonEvent.openModal': openModalAction }"
|
v-on="{ 'buttonEvent.openModal': openModalAction }"
|
||||||
validationRules="option-required"
|
validationRules="option-required"
|
||||||
isRequired />
|
isRequired />
|
||||||
|
|
@ -79,6 +80,10 @@ import { Form, defineRule } from "vee-validate";
|
||||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
import { applicationConfig } from "@/constants/application-config";
|
import { applicationConfig } from "@/constants/application-config";
|
||||||
import { payWithInsuranceStates } from "@/constants/pay-with-insurance-states";
|
import { payWithInsuranceStates } from "@/constants/pay-with-insurance-states";
|
||||||
|
import { revalidatePromosAndValidateNewPromo } from "@/helpers/promotions-helper";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||||
|
import { setTransitionHooks } from "vue";
|
||||||
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -122,14 +127,12 @@ export default {
|
||||||
];
|
];
|
||||||
|
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
const clonedGlassParts = store.getters.order.lineItems.glassParts
|
const nullSafeGlassParts = store.getters.order.lineItems.glassParts ?? [];
|
||||||
? JSON.parse(JSON.stringify(store.getters.order.lineItems.glassParts))
|
|
||||||
: [];
|
|
||||||
const availableLineItems = [
|
const availableLineItems = [
|
||||||
resultMap.rainDefense,
|
resultMap.rainDefense,
|
||||||
...resultMap.supportingItems,
|
...resultMap.supportingItems,
|
||||||
...resultMap.wipers,
|
...resultMap.wipers,
|
||||||
...clonedGlassParts,
|
...nullSafeGlassParts,
|
||||||
];
|
];
|
||||||
|
|
||||||
const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
|
const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
|
@ -146,13 +149,26 @@ export default {
|
||||||
resultMap.supportingItems,
|
resultMap.supportingItems,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Promo logic
|
||||||
|
const promoCodeFromQueryString = getQuerystringParameter(queryStrings.PROMO);
|
||||||
|
|
||||||
|
const { validatePromoResponse, revalidatePromoResponse } =
|
||||||
|
await revalidatePromosAndValidateNewPromo(
|
||||||
|
promoCodeFromQueryString,
|
||||||
|
pricingResults,
|
||||||
|
"quote"
|
||||||
|
);
|
||||||
|
// End of promo logic
|
||||||
|
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.pricedGlassParts = clonedGlassParts;
|
vm.pricedGlassParts = nullSafeGlassParts;
|
||||||
vm.supportingItems = resultMap.supportingItems;
|
vm.supportingItems = resultMap.supportingItems;
|
||||||
vm.availableLineItems = pricingResults;
|
vm.availableLineItems = pricingResults;
|
||||||
vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue(vm.availableLineItems);
|
vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue(vm.availableLineItems);
|
||||||
|
vm.newValidatedPromos = validatePromoResponse?.data.orderPromos;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -162,8 +178,18 @@ export default {
|
||||||
availableLineItems: null,
|
availableLineItems: null,
|
||||||
supportingItems: null,
|
supportingItems: null,
|
||||||
pricedGlassParts: null,
|
pricedGlassParts: null,
|
||||||
|
newValidatedPromos: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
allActivePromos() {
|
||||||
|
const allActivePromos = [];
|
||||||
|
if (this.newValidatedPromos) allActivePromos.push(...this.newValidatedPromos);
|
||||||
|
if (this.$store.getters.order.lineItems.promos)
|
||||||
|
allActivePromos.push(...this.$store.getters.order.lineItems.promos);
|
||||||
|
return allActivePromos;
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openModalAction(modalName) {
|
openModalAction(modalName) {
|
||||||
this.$refs[modalName].openModal();
|
this.$refs[modalName].openModal();
|
||||||
|
|
@ -239,6 +265,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false);
|
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false);
|
||||||
|
this.dispatchStoreAction(this.storeActions.SAVE_PROMOS, this.newValidatedPromos, false);
|
||||||
|
|
||||||
const payment = this.$store.getters.payment;
|
const payment = this.$store.getters.payment;
|
||||||
if (payment.isInsurance) {
|
if (payment.isInsurance) {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@ import {
|
||||||
containsLineItemWithPartType,
|
containsLineItemWithPartType,
|
||||||
findLineItemsWithPartType,
|
findLineItemsWithPartType,
|
||||||
} from "@/helpers/service-package-helper";
|
} from "@/helpers/service-package-helper";
|
||||||
|
import {
|
||||||
|
getPromosThatMatchLineItemsOnOrder,
|
||||||
|
removeVapsPromosFromPromoArray,
|
||||||
|
} from "@/helpers/promotions-helper";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "servicePackageQuestion",
|
name: "servicePackageQuestion",
|
||||||
|
|
@ -40,6 +44,7 @@ export default {
|
||||||
isRequired: Boolean,
|
isRequired: Boolean,
|
||||||
isInsuranceSelected: Boolean,
|
isInsuranceSelected: Boolean,
|
||||||
availableLineItems: null,
|
availableLineItems: null,
|
||||||
|
activePromos: null,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -86,8 +91,11 @@ export default {
|
||||||
buttonLabel: this.getHeaderTextFromCms(answer.SubWidgetName),
|
buttonLabel: this.getHeaderTextFromCms(answer.SubWidgetName),
|
||||||
buttonLabelSubCopy: this.getSubheaderTextFromCms(answer.SubWidgetName),
|
buttonLabelSubCopy: this.getSubheaderTextFromCms(answer.SubWidgetName),
|
||||||
buttonBodyCopy: this.getBodyTextFromCms(answer.SubWidgetName),
|
buttonBodyCopy: this.getBodyTextFromCms(answer.SubWidgetName),
|
||||||
buttonAuxillaryCopy: this.getPackagePriceString(answer.Name),
|
buttonAuxillaryCopy: this.getDiscountedPackagePriceString(answer.Name),
|
||||||
buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName),
|
buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName),
|
||||||
|
additionalButtonData: {
|
||||||
|
strikeThroughPrice: this.getPackagePriceString(answer.Name),
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
return modifiedAnswers;
|
return modifiedAnswers;
|
||||||
},
|
},
|
||||||
|
|
@ -161,21 +169,33 @@ export default {
|
||||||
return this.processIfStatements(footerText, "custom", this.getCustomValueFromString);
|
return this.processIfStatements(footerText, "custom", this.getCustomValueFromString);
|
||||||
},
|
},
|
||||||
getPackagePriceString(packageName) {
|
getPackagePriceString(packageName) {
|
||||||
const formattedPriceFloat = parseFloat(this.getPackagePrice(packageName)).toFixed(2);
|
const formattedPriceFloat = parseFloat(
|
||||||
|
this.getPackagePrice(packageName, { discountedPrice: false })
|
||||||
|
).toFixed(2);
|
||||||
|
return "$" + formattedPriceFloat;
|
||||||
|
},
|
||||||
|
getDiscountedPackagePriceString(packageName) {
|
||||||
|
const formattedPriceFloat = parseFloat(
|
||||||
|
this.getPackagePrice(packageName, { discountedPrice: true })
|
||||||
|
).toFixed(2);
|
||||||
return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat;
|
return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat;
|
||||||
},
|
},
|
||||||
getPackagePrice(packageName) {
|
getPackagePrice(packageName, { discountedPrice = false }) {
|
||||||
|
const lineItemsToPrice = [...this.nullSafeAvailableLineItems];
|
||||||
|
if (discountedPrice) {
|
||||||
|
lineItemsToPrice.push(...removeVapsPromosFromPromoArray(this.activePromos));
|
||||||
|
}
|
||||||
let priceFloat = this.isInsuranceSelected
|
let priceFloat = this.isInsuranceSelected
|
||||||
? 0
|
? 0
|
||||||
: baseMixin.methods.getTierOnePackagePrice(
|
: baseMixin.methods.getTierOnePackagePrice(
|
||||||
baseMixin.methods.filterOutFees(this.nullSafeAvailableLineItems)
|
baseMixin.methods.filterOutFees(lineItemsToPrice)
|
||||||
);
|
);
|
||||||
|
|
||||||
priceFloat += this.getVapsPrice(packageName);
|
priceFloat += this.getVapsPrice(packageName, discountedPrice);
|
||||||
|
|
||||||
return priceFloat;
|
return priceFloat;
|
||||||
},
|
},
|
||||||
getVapsPrice(packageName) {
|
getVapsPrice(packageName, applyPromoDiscounts = false) {
|
||||||
const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName);
|
const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName);
|
||||||
|
|
||||||
let price = 0;
|
let price = 0;
|
||||||
|
|
@ -184,6 +204,16 @@ export default {
|
||||||
price += baseMixin.methods.getTotalLineItemPrice(item);
|
price += baseMixin.methods.getTotalLineItemPrice(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (applyPromoDiscounts && this.activePromos) {
|
||||||
|
const relevantPromos = getPromosThatMatchLineItemsOnOrder(
|
||||||
|
this.activePromos,
|
||||||
|
vapsItems
|
||||||
|
);
|
||||||
|
relevantPromos.forEach((promo) => {
|
||||||
|
price += baseMixin.methods.getTotalLineItemPrice(promo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return price;
|
return price;
|
||||||
},
|
},
|
||||||
selectDefaultPackage() {
|
selectDefaultPackage() {
|
||||||
|
|
|
||||||
|
|
@ -494,6 +494,9 @@ export default {
|
||||||
this.updateAndSaveSupportingItems();
|
this.updateAndSaveSupportingItems();
|
||||||
this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route);
|
this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route);
|
||||||
},
|
},
|
||||||
|
openModalAction(modalName) {
|
||||||
|
this.$refs[modalName].openModal();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
selectedAppointmentType: {
|
selectedAppointmentType: {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import store from "@/store";
|
||||||
import analyticsMixin from "@/mixins/analytics-mixin";
|
import analyticsMixin from "@/mixins/analytics-mixin";
|
||||||
import { experimentTriggers } from "../constants/experiments";
|
import { experimentTriggers } from "../constants/experiments";
|
||||||
import { applicationConfig } from "../constants/application-config";
|
import { applicationConfig } from "../constants/application-config";
|
||||||
|
import { shouldStripPromoQueryString } from "@/helpers/promotions-helper";
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
|
|
@ -283,7 +284,7 @@ async function navigate(
|
||||||
queryStringsObject[queryStrings.ZIP_CODE] = zip;
|
queryStringsObject[queryStrings.ZIP_CODE] = zip;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (promo) {
|
if (promo && !shouldStripPromoQueryString(currentRoute.query.fmgPage)) {
|
||||||
queryStringsObject[queryStrings.PROMO] = promo;
|
queryStringsObject[queryStrings.PROMO] = promo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper
|
||||||
import { deepEqual } from "@/helpers/object-helper";
|
import { deepEqual } from "@/helpers/object-helper";
|
||||||
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants";
|
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants";
|
||||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||||
|
import { deepClone } from "@/helpers/object-helper";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||||
import {
|
import {
|
||||||
|
|
@ -84,6 +85,7 @@ const getDefaultState = () => {
|
||||||
supportingItems: null,
|
supportingItems: null,
|
||||||
vaps: null,
|
vaps: null,
|
||||||
serverData: null,
|
serverData: null,
|
||||||
|
promos: null,
|
||||||
},
|
},
|
||||||
payment: {
|
payment: {
|
||||||
isInsurance: null,
|
isInsurance: null,
|
||||||
|
|
@ -94,6 +96,7 @@ const getDefaultState = () => {
|
||||||
parentAccountNumber: 0,
|
parentAccountNumber: 0,
|
||||||
payNowType: "cc",
|
payNowType: "cc",
|
||||||
piaErrorCode: null,
|
piaErrorCode: null,
|
||||||
|
inactivePromos: null,
|
||||||
},
|
},
|
||||||
schedule: {
|
schedule: {
|
||||||
date: null,
|
date: null,
|
||||||
|
|
@ -194,6 +197,12 @@ export const mutations = {
|
||||||
updateLineItemsServerData(state, serverData) {
|
updateLineItemsServerData(state, serverData) {
|
||||||
state.order.lineItems.serverData = serverData;
|
state.order.lineItems.serverData = serverData;
|
||||||
},
|
},
|
||||||
|
updateInactivePromos(state, inactivePromos) {
|
||||||
|
state.order.payment.inactivePromos = inactivePromos;
|
||||||
|
},
|
||||||
|
updatePromos(state, promos) {
|
||||||
|
state.order.lineItems.promos = promos;
|
||||||
|
},
|
||||||
updatePageData(state, pageData) {
|
updatePageData(state, pageData) {
|
||||||
state.applicationUser.pageData[pageData.page] = pageData.data;
|
state.applicationUser.pageData[pageData.page] = pageData.data;
|
||||||
},
|
},
|
||||||
|
|
@ -1234,10 +1243,10 @@ export const actions = {
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
|
|
||||||
getWipers(context, { pageNameToLog }) {
|
async getWipers(context, { pageNameToLog }) {
|
||||||
const carId = context.getters.vehicle.carId;
|
const carId = context.getters.vehicle.carId;
|
||||||
const serviceZipCode = context.getters.order.serviceLocation.zipCode;
|
const serviceZipCode = context.getters.order.serviceLocation.zipCode;
|
||||||
return globalMethods
|
const response = await globalMethods
|
||||||
.callHttpClient({
|
.callHttpClient({
|
||||||
method: endpoints.GetWipers.method,
|
method: endpoints.GetWipers.method,
|
||||||
endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}`,
|
endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}`,
|
||||||
|
|
@ -1248,15 +1257,20 @@ export const actions = {
|
||||||
// The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow
|
// The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
syncLineItemIds(response.data, context.getters.order.lineItems.vaps);
|
||||||
|
return response;
|
||||||
},
|
},
|
||||||
|
|
||||||
getRainDefense(context, { pageNameToLog }) {
|
async getRainDefense(context, { pageNameToLog }) {
|
||||||
return globalMethods.callHttpClient({
|
const response = await globalMethods.callHttpClient({
|
||||||
method: endpoints.GetRainDefense.method,
|
method: endpoints.GetRainDefense.method,
|
||||||
endpoint: endpoints.GetRainDefense.url,
|
endpoint: endpoints.GetRainDefense.url,
|
||||||
logApiCall: true,
|
logApiCall: true,
|
||||||
pageNameToLog: pageNameToLog,
|
pageNameToLog: pageNameToLog,
|
||||||
});
|
});
|
||||||
|
syncLineItemIds([response.data], context.getters.order.lineItems.vaps);
|
||||||
|
return response;
|
||||||
},
|
},
|
||||||
|
|
||||||
getMobileFeePart(context, { pageNameToLog }) {
|
getMobileFeePart(context, { pageNameToLog }) {
|
||||||
|
|
@ -1536,6 +1550,7 @@ export const actions = {
|
||||||
endpoint: endpoints.SaveSession.url,
|
endpoint: endpoints.SaveSession.url,
|
||||||
payload: {
|
payload: {
|
||||||
submitAfterSave: context.state.submitAfterSave,
|
submitAfterSave: context.state.submitAfterSave,
|
||||||
|
userAgent: navigator.userAgent,
|
||||||
applicationUser: {
|
applicationUser: {
|
||||||
crmCustomerId: applicationUser.crmCustomerId,
|
crmCustomerId: applicationUser.crmCustomerId,
|
||||||
experiments: applicationUser.experiments,
|
experiments: applicationUser.experiments,
|
||||||
|
|
@ -1581,6 +1596,7 @@ export const actions = {
|
||||||
supportingItems: lineItems.supportingItems,
|
supportingItems: lineItems.supportingItems,
|
||||||
vaps: lineItems.vaps,
|
vaps: lineItems.vaps,
|
||||||
serverData: lineItems.serverData,
|
serverData: lineItems.serverData,
|
||||||
|
promos: lineItems.promos,
|
||||||
},
|
},
|
||||||
payment: {
|
payment: {
|
||||||
InsuranceCoverage: {
|
InsuranceCoverage: {
|
||||||
|
|
@ -1588,6 +1604,7 @@ export const actions = {
|
||||||
},
|
},
|
||||||
isInsurance: order.payment.isInsurance,
|
isInsurance: order.payment.isInsurance,
|
||||||
parentAccountNumber: order.payment.parentAccountNumber,
|
parentAccountNumber: order.payment.parentAccountNumber,
|
||||||
|
inactivePromos: order.payment.inactivePromos,
|
||||||
},
|
},
|
||||||
serviceLocation: {
|
serviceLocation: {
|
||||||
streetAddress: order.serviceLocation.address,
|
streetAddress: order.serviceLocation.address,
|
||||||
|
|
@ -2006,17 +2023,21 @@ export const actions = {
|
||||||
if (!deepEqual(supportingItems, context.state.order.lineItems.supportingItems)) {
|
if (!deepEqual(supportingItems, context.state.order.lineItems.supportingItems)) {
|
||||||
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
|
||||||
}
|
}
|
||||||
|
addGuidToLineItemsIfNotAlreadyThere(supportingItems);
|
||||||
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems);
|
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveSupportingItemsSuppressingStateResetting(context, supportingItems) {
|
saveSupportingItemsSuppressingStateResetting(context, supportingItems) {
|
||||||
|
addGuidToLineItemsIfNotAlreadyThere(supportingItems);
|
||||||
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems);
|
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveVaps(context, vaps) {
|
saveVaps(context, vaps) {
|
||||||
|
addGuidToLineItemsIfNotAlreadyThere(vaps);
|
||||||
context.commit(storeMutations.UPDATE_VAPS, vaps);
|
context.commit(storeMutations.UPDATE_VAPS, vaps);
|
||||||
},
|
},
|
||||||
|
savePromos(context, promos) {
|
||||||
|
context.commit(storeMutations.UPDATE_PROMOS, promos);
|
||||||
|
},
|
||||||
|
|
||||||
// Price order actions
|
// Price order actions
|
||||||
async priceOrderItemsAndSaveServerData(
|
async priceOrderItemsAndSaveServerData(
|
||||||
|
|
@ -2026,14 +2047,18 @@ export const actions = {
|
||||||
const zipCodeToUse = serviceZipCode
|
const zipCodeToUse = serviceZipCode
|
||||||
? serviceZipCode
|
? serviceZipCode
|
||||||
: context.getters.order.serviceLocation.zipCode;
|
: context.getters.order.serviceLocation.zipCode;
|
||||||
|
|
||||||
const ctuToUse = serviceZipCodeCtu
|
const ctuToUse = serviceZipCodeCtu
|
||||||
? serviceZipCodeCtu
|
? serviceZipCodeCtu
|
||||||
: context.getters.order.serviceLocation.zipCodeCtu;
|
: context.getters.order.serviceLocation.zipCodeCtu;
|
||||||
|
|
||||||
const flattenedLineItemsWithChildParts =
|
const flattenedLineItemsWithChildParts =
|
||||||
getFlattenedArrayOfLineItemsWithChildParts(availableLineItems);
|
getFlattenedArrayOfLineItemsWithChildParts(availableLineItems);
|
||||||
|
|
||||||
const lineItemsWithOnlyPartNumbers = flattenedLineItemsWithChildParts.map((lineItem) => ({
|
const lineItemsWithOnlyPartNumbers = flattenedLineItemsWithChildParts.map((lineItem) => ({
|
||||||
partNumber: lineItem.partNumber,
|
partNumber: lineItem.partNumber,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const availableLineItemsFormattedForRequest =
|
const availableLineItemsFormattedForRequest =
|
||||||
buildQueryStringParameterFromArrayOfComplexObjects(
|
buildQueryStringParameterFromArrayOfComplexObjects(
|
||||||
lineItemsWithOnlyPartNumbers,
|
lineItemsWithOnlyPartNumbers,
|
||||||
|
|
@ -2067,9 +2092,160 @@ export const actions = {
|
||||||
|
|
||||||
context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData);
|
context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData);
|
||||||
|
|
||||||
availableLineItems = addPricesToLineItems(availableLineItems, response.data.lineItems);
|
const pricedLineItems = addPricesToLineItems(availableLineItems, response.data.lineItems);
|
||||||
|
|
||||||
return availableLineItems;
|
return pricedLineItems;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Tax order actions
|
||||||
|
async taxOrderItemsAndSaveServerData(
|
||||||
|
context,
|
||||||
|
{
|
||||||
|
payload: {
|
||||||
|
billToAccountNumber,
|
||||||
|
providerNumber,
|
||||||
|
appointmentType,
|
||||||
|
serviceLocationState,
|
||||||
|
serviceLocationZipCode,
|
||||||
|
pricedLineItems,
|
||||||
|
},
|
||||||
|
pageNameToLog,
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const flattenedLineItemsWithChildParts =
|
||||||
|
getFlattenedArrayOfLineItemsWithChildParts(pricedLineItems);
|
||||||
|
|
||||||
|
const lineItemsWithOnlyPriceInfo = flattenedLineItemsWithChildParts.map((lineItem) => ({
|
||||||
|
partNumber: lineItem.partNumber,
|
||||||
|
laborAmount: lineItem.laborAmount,
|
||||||
|
kitPrice: lineItem.kitPrice,
|
||||||
|
sellingPrice: lineItem.sellingPrice,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const pricedLineItemsFormattedForRequest =
|
||||||
|
buildQueryStringParameterFromArrayOfComplexObjects(
|
||||||
|
lineItemsWithOnlyPriceInfo,
|
||||||
|
"lineItems"
|
||||||
|
);
|
||||||
|
|
||||||
|
let queryString =
|
||||||
|
`ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` +
|
||||||
|
`&BillToAccountNumber=${billToAccountNumber}` +
|
||||||
|
`&ProviderNumber=${providerNumber}` +
|
||||||
|
`&AppointmentType=${appointmentType}` +
|
||||||
|
`&ServiceLocation.State=${serviceLocationState}` +
|
||||||
|
`&ServiceLocation.ZipCode=${serviceLocationZipCode}` +
|
||||||
|
`&${pricedLineItemsFormattedForRequest}`;
|
||||||
|
|
||||||
|
const lineItemServerData = context.getters.order.lineItems.serverData;
|
||||||
|
if (lineItemServerData) {
|
||||||
|
queryString += `&ServerData=${encodeURIComponent(lineItemServerData)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await globalMethods.callHttpClient({
|
||||||
|
method: endpoints.TaxOrderItems.method,
|
||||||
|
endpoint: `${endpoints.TaxOrderItems.url}?${queryString}`,
|
||||||
|
logApiCall: true,
|
||||||
|
pageNameToLog: pageNameToLog,
|
||||||
|
});
|
||||||
|
|
||||||
|
context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData);
|
||||||
|
|
||||||
|
const taxedLineItems = addTaxesToPricedLineItems(
|
||||||
|
pricedLineItems,
|
||||||
|
response.data.taxedLineItems
|
||||||
|
);
|
||||||
|
|
||||||
|
return taxedLineItems;
|
||||||
|
},
|
||||||
|
|
||||||
|
async validateOrderPromoAndSaveServerData(
|
||||||
|
context,
|
||||||
|
{ payload: { promoCode, addableVaps }, pageNameToLog }
|
||||||
|
) {
|
||||||
|
const order = context.getters.order;
|
||||||
|
addGuidToLineItemsIfNotAlreadyThere(addableVaps);
|
||||||
|
const requestObject = {
|
||||||
|
promoCode: promoCode,
|
||||||
|
order: {
|
||||||
|
appointmentType: order.serviceLocation.appointmentType,
|
||||||
|
carId: order.vehicle.carId,
|
||||||
|
correlationId: order.referralCorrelationId,
|
||||||
|
eon: order.eon,
|
||||||
|
isRepair: order.damage.isRepair,
|
||||||
|
glassToReplace: renameGlassToReplaceAttributes(order.damage.glassToReplace),
|
||||||
|
lineItemsOnOrder: getArrayOfAllLineItems(order.lineItems),
|
||||||
|
addableVaps: addableVaps,
|
||||||
|
parentAccountNumber: order.payment.parentAccountNumber,
|
||||||
|
referralSequenceNumber: order.referralSequenceNumber,
|
||||||
|
serviceState: order.serviceLocation.state,
|
||||||
|
serverData: order.lineItems.serverData,
|
||||||
|
vehicleYear: "" + order.vehicle.year,
|
||||||
|
zipCodeOrProviderCtu:
|
||||||
|
order.serviceLocation.appointmentType === "Inshop"
|
||||||
|
? order.serviceLocation.provider.address.zipCodeCtu
|
||||||
|
: order.serviceLocation.zipCodeCtu,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateResponse = await globalMethods.callHttpClient({
|
||||||
|
method: endpoints.ValidatePromo.method,
|
||||||
|
endpoint: endpoints.ValidatePromo.url,
|
||||||
|
payload: requestObject,
|
||||||
|
logApiCall: true,
|
||||||
|
pageNameToLog: pageNameToLog,
|
||||||
|
});
|
||||||
|
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA,
|
||||||
|
validateResponse.data.lineItemsServerData
|
||||||
|
);
|
||||||
|
|
||||||
|
return validateResponse;
|
||||||
|
},
|
||||||
|
async revalidateOrderPromosAndUpdateStore(context, { pageNameToLog }) {
|
||||||
|
const order = context.getters.order;
|
||||||
|
|
||||||
|
let requestObject = {
|
||||||
|
inactivePromos: order.payment.inactivePromos,
|
||||||
|
order: {
|
||||||
|
appointmentType: order.serviceLocation.appointmentType,
|
||||||
|
carId: order.vehicle.carId,
|
||||||
|
correlationId: order.referralCorrelationId,
|
||||||
|
eon: order.eon,
|
||||||
|
isRepair: order.damage.isRepair,
|
||||||
|
glassToReplace: renameGlassToReplaceAttributes(order.damage.glassToReplace),
|
||||||
|
lineItemsOnOrder: getArrayOfAllLineItems(order.lineItems),
|
||||||
|
parentAccountNumber: order.payment.parentAccountNumber,
|
||||||
|
referralSequenceNumber: order.referralSequenceNumber,
|
||||||
|
serviceState: order.serviceLocation.state,
|
||||||
|
serverData: order.lineItems.serverData,
|
||||||
|
vehicleYear: "" + order.vehicle.year,
|
||||||
|
zipCodeOrProviderCtu:
|
||||||
|
order.serviceLocation.appointmentType === "Inshop"
|
||||||
|
? order.serviceLocation.provider.address.zipCodeCtu
|
||||||
|
: order.serviceLocation.zipCodeCtu,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const revalidateResponse = await globalMethods.callHttpClient({
|
||||||
|
method: endpoints.RevalidatePromos.method,
|
||||||
|
endpoint: endpoints.RevalidatePromos.url,
|
||||||
|
payload: requestObject,
|
||||||
|
logApiCall: true,
|
||||||
|
pageNameToLog: pageNameToLog,
|
||||||
|
});
|
||||||
|
|
||||||
|
const revalidationErrorPromoCodes = revalidateResponse.data.errors.map((x) => x.promoCode);
|
||||||
|
|
||||||
|
context.commit(storeMutations.UPDATE_PROMOS, revalidateResponse.data.promoLineItems);
|
||||||
|
context.commit(storeMutations.UPDATE_INACTIVE_PROMOS, revalidationErrorPromoCodes);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA,
|
||||||
|
revalidateResponse.data.lineItemsServerData
|
||||||
|
);
|
||||||
|
|
||||||
|
return revalidateResponse;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Misc order actions
|
// Misc order actions
|
||||||
|
|
@ -2136,7 +2312,7 @@ export const actions = {
|
||||||
if (!deepEqual(parts, context.state.order.lineItems.glassParts)) {
|
if (!deepEqual(parts, context.state.order.lineItems.glassParts)) {
|
||||||
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
|
||||||
}
|
}
|
||||||
|
addGuidToLineItemsIfNotAlreadyThere(parts);
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, parts);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, parts);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -2277,21 +2453,55 @@ function convertGlassPieceNamingFromApi(glassArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPricesToLineItems(lineItems, pricingLineItems) {
|
function addPricesToLineItems(lineItems, pricingLineItems) {
|
||||||
lineItems.forEach((lineItem) => {
|
const pricedLineItems = deepClone(lineItems);
|
||||||
|
pricedLineItems.forEach((lineItem) => {
|
||||||
let lineItemIndex = pricingLineItems.findIndex(
|
let lineItemIndex = pricingLineItems.findIndex(
|
||||||
(pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber
|
(pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber
|
||||||
);
|
);
|
||||||
|
|
||||||
if (lineItem.childParts) {
|
if (lineItem.childParts) {
|
||||||
addPricesToLineItems(lineItem.childParts, pricingLineItems);
|
addPricesToLineItems(lineItem.childParts, pricingLineItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0];
|
let pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0];
|
||||||
lineItem.laborAmount = pricedLineItem.laborAmount;
|
lineItem.laborAmount = pricedLineItem.laborAmount;
|
||||||
lineItem.sellingPrice = pricedLineItem.sellingPrice;
|
lineItem.sellingPrice = pricedLineItem.sellingPrice;
|
||||||
lineItem.kitPrice = pricedLineItem.kitPrice;
|
lineItem.kitPrice = pricedLineItem.kitPrice;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return pricedLineItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTaxesToPricedLineItems(lineItems, taxingLineItems) {
|
||||||
|
lineItems.forEach((lineItem) => {
|
||||||
|
let lineItemIndex = taxingLineItems.findIndex(
|
||||||
|
(taxingLineItem) => taxingLineItem.partNumber === lineItem.partNumber
|
||||||
|
);
|
||||||
|
|
||||||
|
if (lineItem.childParts) {
|
||||||
|
addTaxesToPricedLineItems(lineItem.childParts, taxingLineItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
let taxedLineItem = taxingLineItems.splice(lineItemIndex, 1)[0];
|
||||||
|
lineItem.SalesTax = taxedLineItem.SalesTax;
|
||||||
|
});
|
||||||
|
|
||||||
return lineItems;
|
return lineItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getArrayOfAllLineItems(lineItems) {
|
||||||
|
let consolidatedLineItemsArray = [];
|
||||||
|
if (lineItems.glassParts != null)
|
||||||
|
consolidatedLineItemsArray = [...consolidatedLineItemsArray, ...lineItems.glassParts];
|
||||||
|
if (lineItems.supportingItems != null)
|
||||||
|
consolidatedLineItemsArray = [...consolidatedLineItemsArray, ...lineItems.supportingItems];
|
||||||
|
if (lineItems.vaps != null)
|
||||||
|
consolidatedLineItemsArray = [...consolidatedLineItemsArray, ...lineItems.vaps];
|
||||||
|
if (lineItems.promos != null)
|
||||||
|
consolidatedLineItemsArray = [...consolidatedLineItemsArray, ...lineItems.promos];
|
||||||
|
return consolidatedLineItemsArray;
|
||||||
|
}
|
||||||
|
|
||||||
function getFlattenedArrayOfLineItemsWithChildParts(lineItems) {
|
function getFlattenedArrayOfLineItemsWithChildParts(lineItems) {
|
||||||
let flattenedArray = [];
|
let flattenedArray = [];
|
||||||
lineItems?.forEach((lineItem) => {
|
lineItems?.forEach((lineItem) => {
|
||||||
|
|
@ -2326,6 +2536,37 @@ function convertGlassPieceToBackEndCompatibleFormat(glassPieces) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renameGlassToReplaceAttributes(glassToReplace) {
|
||||||
|
let newGlassToReplace = [];
|
||||||
|
if (glassToReplace) {
|
||||||
|
glassToReplace.forEach((item) => {
|
||||||
|
newGlassToReplace.push({ location: item.glassLocation, name: item.glassName });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return newGlassToReplace;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addGuidToLineItemsIfNotAlreadyThere(lineItems) {
|
||||||
|
lineItems.forEach((lineItem) => {
|
||||||
|
if (!lineItem.id) {
|
||||||
|
lineItem.id = crypto.randomUUID();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncLineItemIds(lineItemsWithoutIds, lineItemsWithIds) {
|
||||||
|
if (!lineItemsWithIds || !lineItemsWithoutIds) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lineItemsWithoutIds.forEach((noId) => {
|
||||||
|
lineItemsWithIds.forEach((withId) => {
|
||||||
|
if (noId.partNumber === withId.partNumber && noId.partType === withId.partType) {
|
||||||
|
noId.id = withId.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function providersEqual(providerA, providerB) {
|
function providersEqual(providerA, providerB) {
|
||||||
return (
|
return (
|
||||||
providerA.providerNumber === providerB.providerNumber &&
|
providerA.providerNumber === providerB.providerNumber &&
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
||||||
// Mock global method
|
// Mock global method
|
||||||
globalMethods.callHttpClient = jest.fn();
|
globalMethods.callHttpClient = jest.fn();
|
||||||
|
|
||||||
|
global.crypto = { randomUUID: jest.fn() };
|
||||||
|
|
||||||
describe("Mutations", () => {
|
describe("Mutations", () => {
|
||||||
it("Updates vehicle year in state", () => {
|
it("Updates vehicle year in state", () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -1378,6 +1380,8 @@ describe("Actions", () => {
|
||||||
state: state,
|
state: state,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
context.state.order.lineItems = [];
|
||||||
|
|
||||||
const commit = jest.fn();
|
const commit = jest.fn();
|
||||||
const dispatch = jest.fn();
|
const dispatch = jest.fn();
|
||||||
|
|
||||||
|
|
@ -1385,10 +1389,10 @@ describe("Actions", () => {
|
||||||
context.dispatch = dispatch;
|
context.dispatch = dispatch;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
actions.saveGlassParts(context, { glassParts: {} });
|
actions.saveGlassParts(context, []);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, { glassParts: {} });
|
expect(commit).toBeCalledWith(storeMutations.UPDATE_GLASS_PARTS, []);
|
||||||
expect(dispatch).toBeCalledWith(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
|
expect(dispatch).toBeCalledWith(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1417,7 +1421,7 @@ describe("Actions", () => {
|
||||||
state: {
|
state: {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
supportingItems: ["TestValue1", "TestValue2"],
|
supportingItems: [{ partNum: "TestValue1" }, { partNum: "TestValue2" }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -1430,7 +1434,11 @@ describe("Actions", () => {
|
||||||
context.dispatch = dispatch;
|
context.dispatch = dispatch;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
actions.saveSupportingItems(context, ["TestValue3", "TestValue4", "TestValue5"]);
|
actions.saveSupportingItems(context, [
|
||||||
|
{ partNum: "TestValue3" },
|
||||||
|
{ partNum: "TestValue4" },
|
||||||
|
{ partNum: "TestValue5" },
|
||||||
|
]);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(dispatch).toBeCalledWith(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
|
expect(dispatch).toBeCalledWith(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES);
|
||||||
|
|
@ -1442,7 +1450,7 @@ describe("Actions", () => {
|
||||||
state: {
|
state: {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
supportingItems: ["TestValue1", "TestValue2"],
|
supportingItems: [{ partNum: "TestValue1" }, { partNum: "TestValue2" }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -1455,7 +1463,10 @@ describe("Actions", () => {
|
||||||
context.dispatch = dispatch;
|
context.dispatch = dispatch;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
actions.saveSupportingItems(context, ["TestValue1", "TestValue2"]);
|
actions.saveSupportingItems(context, [
|
||||||
|
{ partNum: "TestValue1" },
|
||||||
|
{ partNum: "TestValue2" },
|
||||||
|
]);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(dispatch).not.toBeCalledWith(
|
expect(dispatch).not.toBeCalledWith(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue