Merge pull request #1855 from Safelite/feature/CSR-1994
Feature/csr 1994
This commit is contained in:
commit
cb8e542672
15 changed files with 507 additions and 43 deletions
|
|
@ -3,6 +3,7 @@ const cartItemCategories = {
|
||||||
GLASS_PARTS: "glassParts",
|
GLASS_PARTS: "glassParts",
|
||||||
SUPPORTING_ITEMS: "supportingItems",
|
SUPPORTING_ITEMS: "supportingItems",
|
||||||
PROMOS: "promos",
|
PROMOS: "promos",
|
||||||
|
SERVICE_PACKAGE_DISCOUNT: "servicePackageDiscount",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { cartItemCategories };
|
export { cartItemCategories };
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ const cartItemTypes = {
|
||||||
PROMOS: "PROMOS",
|
PROMOS: "PROMOS",
|
||||||
EARLY_BIRD: "EARLY BIRD",
|
EARLY_BIRD: "EARLY BIRD",
|
||||||
SUPPLIES_REPAIR: "SUPPLIES-REPAIR",
|
SUPPLIES_REPAIR: "SUPPLIES-REPAIR",
|
||||||
|
SERVICE_PACKAGE_DISCOUNT: "SERVICE PACKAGE DISCOUNT",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { cartItemTypes };
|
export { cartItemTypes };
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,10 @@ const endpoints = {
|
||||||
url: "/parts/api/v1/parts/mobile-fee",
|
url: "/parts/api/v1/parts/mobile-fee",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
},
|
},
|
||||||
|
CashServicePackageDiscount: {
|
||||||
|
url: "/parts/api/v1/parts/service-package-discount",
|
||||||
|
method: "POST",
|
||||||
|
},
|
||||||
GetServiceabilityDetails: {
|
GetServiceabilityDetails: {
|
||||||
url: "/location/api/v1/location/serviceability-details",
|
url: "/location/api/v1/location/serviceability-details",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ const experimentSettings = {
|
||||||
PIA_INSURANCE: "DisplayPIAInsurance",
|
PIA_INSURANCE: "DisplayPIAInsurance",
|
||||||
SUBMIT_ORDER_ENABLE_PIA: "SubmitOrder_Enable_PIA",
|
SUBMIT_ORDER_ENABLE_PIA: "SubmitOrder_Enable_PIA",
|
||||||
IS_EMAIL_OPTIONAL: "isEmailOptional",
|
IS_EMAIL_OPTIONAL: "isEmailOptional",
|
||||||
|
SERVICE_PACKAGE_DISCOUNT: "OfferServicePackageDiscount",
|
||||||
};
|
};
|
||||||
|
|
||||||
const experimentTriggers = {
|
const experimentTriggers = {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const partTypeStrings = {
|
||||||
MOBILE_FEE: "MOBILE FEE",
|
MOBILE_FEE: "MOBILE FEE",
|
||||||
REPAIR_FEE: "REPAIR FEE",
|
REPAIR_FEE: "REPAIR FEE",
|
||||||
EARLY_BIRD: "EARLY BIRD",
|
EARLY_BIRD: "EARLY BIRD",
|
||||||
|
SERVICE_PACKAGE_DISCOUNT: "SERVICE PACKAGE DISCOUNT",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { partTypeStrings };
|
export { partTypeStrings };
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ const storeActions = {
|
||||||
GET_PART_FROM_CAPABILITY_QUESTION_ANSWER: "getPartFromCapabilityQuestionAnswer",
|
GET_PART_FROM_CAPABILITY_QUESTION_ANSWER: "getPartFromCapabilityQuestionAnswer",
|
||||||
GET_MOLDING_QUESTIONS: "getMoldingQuestions",
|
GET_MOLDING_QUESTIONS: "getMoldingQuestions",
|
||||||
GET_MOBILE_FEE_PART: "getMobileFeePart",
|
GET_MOBILE_FEE_PART: "getMobileFeePart",
|
||||||
|
CASH_SERVICE_PACKAGE_DISCOUNT: "cashServicePackageDiscount",
|
||||||
GET_SERVICEABILITY_DETAILS: "getServiceabilityDetails",
|
GET_SERVICEABILITY_DETAILS: "getServiceabilityDetails",
|
||||||
GET_SHOP_TIME_SLOTS: "getShopTimeSlots",
|
GET_SHOP_TIME_SLOTS: "getShopTimeSlots",
|
||||||
GET_MOBILE_TIME_SLOTS: "getMobileTimeSlots",
|
GET_MOBILE_TIME_SLOTS: "getMobileTimeSlots",
|
||||||
|
|
|
||||||
|
|
@ -306,6 +306,49 @@ describe("cart.vue", () => {
|
||||||
expect(found).toBe(true);
|
expect(found).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Service package discount Fee Cart Item
|
||||||
|
test("if there is service package discount fee on the order, a service package discount cart item should be added to the cart", () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = {
|
||||||
|
glassParts: [],
|
||||||
|
supportingItems: [
|
||||||
|
{
|
||||||
|
description: null,
|
||||||
|
id: "bc00294e-6baa-403e-866e-52c267187a15",
|
||||||
|
kitPrice: 0,
|
||||||
|
laborAmount: 0,
|
||||||
|
partNumber: "DISC CASHSAVE70",
|
||||||
|
partType: "SERVICE PACKAGE DISCOUNT",
|
||||||
|
salesTax: null,
|
||||||
|
sellingPrice: -70,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
vaps: [],
|
||||||
|
promos: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const availableVaps = [];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
props: {
|
||||||
|
modelValue: lineItems,
|
||||||
|
availableVaps: availableVaps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.servicePackageDiscountCartItem).not.toBeNull();
|
||||||
|
expect(wrapper.vm.servicePackageDiscountCartItem.subTotal).toEqual(-70);
|
||||||
|
expect(wrapper.vm.servicePackageDiscountCartItem.salesTax).toEqual(0);
|
||||||
|
|
||||||
|
const found =
|
||||||
|
wrapper.vm.cartItems.findIndex(
|
||||||
|
(cartItem) => cartItem == wrapper.vm.servicePackageDiscountCartItem
|
||||||
|
) >= 0;
|
||||||
|
expect(found).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
// Other Supporting Items Cart Item
|
// Other Supporting Items Cart Item
|
||||||
test("if there are other supporting items on the order, an other supporting items cart item should be added to the cart but should not be displayed", () => {
|
test("if there are other supporting items on the order, an other supporting items cart item should be added to the cart but should not be displayed", () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,13 @@ export default {
|
||||||
|
|
||||||
return subTotal;
|
return subTotal;
|
||||||
},
|
},
|
||||||
|
getServicePackageDiscount() {
|
||||||
|
const servicePackageDiscountLineItems = this.servicePackageDiscountCartItem;
|
||||||
|
let subTotal = 0;
|
||||||
|
|
||||||
|
subTotal += servicePackageDiscountLineItems?.subTotal;
|
||||||
|
return subTotal;
|
||||||
|
},
|
||||||
getVapsCartItemsForSelectedPackage(packageName) {
|
getVapsCartItemsForSelectedPackage(packageName) {
|
||||||
const packageContentTypes = getPackageContents(
|
const packageContentTypes = getPackageContents(
|
||||||
this.glassToReplace,
|
this.glassToReplace,
|
||||||
|
|
@ -265,7 +272,7 @@ export default {
|
||||||
|
|
||||||
getLineItemAmount(amount, useVerifyingText, category) {
|
getLineItemAmount(amount, useVerifyingText, category) {
|
||||||
if (useVerifyingText) return this.verifyingCoverageText;
|
if (useVerifyingText) return this.verifyingCoverageText;
|
||||||
return category == "promos"
|
return category == ("promos" && "servicePackageDiscount")
|
||||||
? "(" + this.currencyFormatter.format(amount * -1) + ")"
|
? "(" + this.currencyFormatter.format(amount * -1) + ")"
|
||||||
: this.currencyFormatter.format(amount);
|
: this.currencyFormatter.format(amount);
|
||||||
},
|
},
|
||||||
|
|
@ -372,6 +379,9 @@ export default {
|
||||||
if (this.mobileFeeCartItem) {
|
if (this.mobileFeeCartItem) {
|
||||||
cartItems.push(this.mobileFeeCartItem);
|
cartItems.push(this.mobileFeeCartItem);
|
||||||
}
|
}
|
||||||
|
if (this.servicePackageDiscountCartItem) {
|
||||||
|
cartItems.push(this.servicePackageDiscountCartItem);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.premiumAppointmentDiscountCartItem) {
|
if (this.premiumAppointmentDiscountCartItem) {
|
||||||
cartItems.push(this.premiumAppointmentDiscountCartItem);
|
cartItems.push(this.premiumAppointmentDiscountCartItem);
|
||||||
|
|
@ -422,6 +432,9 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
packagePrice += this.getVapsPrice(this.packageLevel);
|
packagePrice += this.getVapsPrice(this.packageLevel);
|
||||||
|
if (this.servicePackageDiscountCartItem) {
|
||||||
|
packagePrice -= this.getServicePackageDiscount();
|
||||||
|
}
|
||||||
|
|
||||||
return packagePrice;
|
return packagePrice;
|
||||||
},
|
},
|
||||||
|
|
@ -769,13 +782,58 @@ export default {
|
||||||
|
|
||||||
return cartItem;
|
return cartItem;
|
||||||
},
|
},
|
||||||
|
servicePackageDiscountCartItemName() {
|
||||||
|
return this.getCmsContent("ServicePackageDiscountTextWidget", "Text");
|
||||||
|
},
|
||||||
|
servicePackageDiscountCartItem() {
|
||||||
|
let cartItem = null;
|
||||||
|
|
||||||
|
const servicePackageDiscountLineItem = this.supportingItems.find(
|
||||||
|
(lineItem) => lineItem.partType == partTypeStrings.SERVICE_PACKAGE_DISCOUNT
|
||||||
|
);
|
||||||
|
|
||||||
|
if (servicePackageDiscountLineItem) {
|
||||||
|
cartItem = {
|
||||||
|
name:
|
||||||
|
this.servicePackageDiscountCartItemName +
|
||||||
|
Math.abs(
|
||||||
|
baseMixin.methods.getTotalLineItemPrice(servicePackageDiscountLineItem)
|
||||||
|
),
|
||||||
|
category: cartItemCategories.SERVICE_PACKAGE_DISCOUNT,
|
||||||
|
cartItemType: cartItemTypes.SERVICE_PACKAGE_DISCOUNT,
|
||||||
|
isDisplayed: true,
|
||||||
|
isRemovable: false,
|
||||||
|
subTotal: 0,
|
||||||
|
salesTax: 0,
|
||||||
|
lineItems: [],
|
||||||
|
isCoveredByInsurance: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
servicePackageDiscountLineItem.cartItemType = cartItem.cartItemType;
|
||||||
|
cartItem.lineItems.push(servicePackageDiscountLineItem);
|
||||||
|
|
||||||
|
cartItem.subTotal +=
|
||||||
|
(servicePackageDiscountLineItem.kitPrice ?? 0) +
|
||||||
|
(servicePackageDiscountLineItem.laborAmount ?? 0) +
|
||||||
|
(servicePackageDiscountLineItem.sellingPrice ?? 0);
|
||||||
|
|
||||||
|
cartItem.salesTax += servicePackageDiscountLineItem.salesTax ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cartItem;
|
||||||
|
},
|
||||||
otherSupportingItemsCartItem() {
|
otherSupportingItemsCartItem() {
|
||||||
let cartItem = null;
|
let cartItem = null;
|
||||||
|
|
||||||
// Don't include fees they are part of the package total
|
const servicePackageDiscountLineItem = this.supportingItems.find(
|
||||||
let otherSupportingItemsLineItems = baseMixin.methods.filterOutFees(
|
(lineItem) => lineItem.partType == partTypeStrings.SERVICE_PACKAGE_DISCOUNT
|
||||||
this.supportingItems
|
|
||||||
);
|
);
|
||||||
|
const otherSupportingItems = this.supportingItems.filter((item) => {
|
||||||
|
return item != servicePackageDiscountLineItem;
|
||||||
|
});
|
||||||
|
// Don't include fees they are part of the package total
|
||||||
|
let otherSupportingItemsLineItems =
|
||||||
|
baseMixin.methods.filterOutFees(otherSupportingItems);
|
||||||
|
|
||||||
if (otherSupportingItemsLineItems.length > 0) {
|
if (otherSupportingItemsLineItems.length > 0) {
|
||||||
cartItem = {
|
cartItem = {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import quote from "@/layouts/quote/quote.vue";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
|
import { experimentSettings } from "@/constants/experiments";
|
||||||
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
|
||||||
jest.mock("@/store", () => ({
|
jest.mock("@/store", () => ({
|
||||||
commit: jest.fn(),
|
commit: jest.fn(),
|
||||||
|
|
@ -60,9 +62,14 @@ const mockMixin = {
|
||||||
filterOutFees: jest.fn().mockImplementation(() => {
|
filterOutFees: jest.fn().mockImplementation(() => {
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
|
getSettingValue: jest.fn((settingName) => {
|
||||||
|
if (settingName === experimentSettings.SERVICE_PACKAGE_DISCOUNT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
|
@ -234,8 +241,12 @@ describe("quote.vue", () => {
|
||||||
vehicle: {
|
vehicle: {
|
||||||
cardId: "123",
|
cardId: "123",
|
||||||
},
|
},
|
||||||
|
experimentSettings: {
|
||||||
|
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const { wrapper } = setupMocks({});
|
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();
|
||||||
|
|
||||||
|
|
@ -254,6 +265,47 @@ describe("quote.vue", () => {
|
||||||
// This should have its own test
|
// This should have its own test
|
||||||
//expect(vm.isInsuranceSelected !== null).toBe(true);
|
//expect(vm.isInsuranceSelected !== null).toBe(true);
|
||||||
});
|
});
|
||||||
|
test("Returns true if service package discount setting is true", async () => {
|
||||||
|
//Arrange
|
||||||
|
store.getters = {
|
||||||
|
lineItems: {
|
||||||
|
glassParts: ["item", "item2"],
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
lineItems: {
|
||||||
|
glassParts: ["item", "item2"],
|
||||||
|
},
|
||||||
|
payment: {},
|
||||||
|
serviceLocation: {
|
||||||
|
zipCode: "12345",
|
||||||
|
zipCodeCtu: "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
cardId: "123",
|
||||||
|
},
|
||||||
|
experimentSettings: {
|
||||||
|
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const { wrapper } = setupMocks({});
|
||||||
|
|
||||||
|
wrapper.vm.$route = { query: { isInsurance: "false" } };
|
||||||
|
|
||||||
|
const isServicePackageDiscount = mockMixin.methods.getSettingValue(
|
||||||
|
experimentSettings.SERVICE_PACKAGE_DISCOUNT
|
||||||
|
);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
await quote.beforeRouteEnter.call(
|
||||||
|
wrapper.vm,
|
||||||
|
{ query: { fmgPage: "quote" } },
|
||||||
|
undefined,
|
||||||
|
(c) => c(wrapper.vm)
|
||||||
|
);
|
||||||
|
//Assert
|
||||||
|
expect(isServicePackageDiscount).toBe(true);
|
||||||
|
});
|
||||||
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
|
||||||
store.getters = {
|
store.getters = {
|
||||||
|
|
@ -274,6 +326,9 @@ describe("quote.vue", () => {
|
||||||
vehicle: {
|
vehicle: {
|
||||||
cardId: "123",
|
cardId: "123",
|
||||||
},
|
},
|
||||||
|
experimentSettings: {
|
||||||
|
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$route = { query: { isInsurance: "true" } };
|
wrapper.vm.$route = { query: { isInsurance: "true" } };
|
||||||
|
|
@ -309,6 +364,9 @@ describe("quote.vue", () => {
|
||||||
vehicle: {
|
vehicle: {
|
||||||
cardId: "123",
|
cardId: "123",
|
||||||
},
|
},
|
||||||
|
experimentSettings: {
|
||||||
|
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$route = { query: { isInsurance: "false" } };
|
wrapper.vm.$route = { query: { isInsurance: "false" } };
|
||||||
|
|
@ -345,6 +403,9 @@ describe("quote.vue", () => {
|
||||||
vehicle: {
|
vehicle: {
|
||||||
cardId: "123",
|
cardId: "123",
|
||||||
},
|
},
|
||||||
|
experimentSettings: {
|
||||||
|
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
// Ensure that query param isn't overriding selection
|
// Ensure that query param isn't overriding selection
|
||||||
|
|
@ -381,6 +442,9 @@ describe("quote.vue", () => {
|
||||||
vehicle: {
|
vehicle: {
|
||||||
cardId: "123",
|
cardId: "123",
|
||||||
},
|
},
|
||||||
|
experimentSettings: {
|
||||||
|
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
// Ensure that query param isn't overriding selection
|
// Ensure that query param isn't overriding selection
|
||||||
|
|
@ -418,6 +482,9 @@ describe("quote.vue", () => {
|
||||||
vehicle: {
|
vehicle: {
|
||||||
cardId: "123",
|
cardId: "123",
|
||||||
},
|
},
|
||||||
|
experimentSettings: {
|
||||||
|
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
mockTierOnePrice = 200;
|
mockTierOnePrice = 200;
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
@ -457,6 +524,9 @@ describe("quote.vue", () => {
|
||||||
vehicle: {
|
vehicle: {
|
||||||
cardId: "123",
|
cardId: "123",
|
||||||
},
|
},
|
||||||
|
experimentSettings: {
|
||||||
|
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
mockTierOnePrice = 505;
|
mockTierOnePrice = 505;
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
@ -495,6 +565,9 @@ describe("quote.vue", () => {
|
||||||
vehicle: {
|
vehicle: {
|
||||||
cardId: "123",
|
cardId: "123",
|
||||||
},
|
},
|
||||||
|
experimentSettings: {
|
||||||
|
settingName: "SERVICE_PACKAGE_DISCOUNT",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
wrapper.vm.$route = { query: null };
|
wrapper.vm.$route = { query: null };
|
||||||
|
|
@ -533,6 +606,35 @@ describe("quote.vue", () => {
|
||||||
|
|
||||||
expect(wrapper.vm.lineItems.promos !== null).toBe(true);
|
expect(wrapper.vm.lineItems.promos !== null).toBe(true);
|
||||||
});
|
});
|
||||||
|
test("On forward button action save supporting lineItems", async () => {
|
||||||
|
//Arrange
|
||||||
|
store.getters.payment = {
|
||||||
|
insuranceCoverage: {},
|
||||||
|
isInsurance: false,
|
||||||
|
};
|
||||||
|
store.getters.order = {
|
||||||
|
lineItems: [],
|
||||||
|
payment: {
|
||||||
|
parentAccountNumber: 167132,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
router: {
|
||||||
|
navigateWithSaving: jest.fn(),
|
||||||
|
},
|
||||||
|
route: { quote },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith(
|
||||||
|
"saveSupportingItems",
|
||||||
|
wrapper.vm.lineItems.supportingItems,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function setupMocks({ customMountOptions }) {
|
function setupMocks({ customMountOptions }) {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
:availableLineItems="availableLineItems"
|
:availableLineItems="availableLineItems"
|
||||||
:isInsuranceSelected="isInsuranceSelected"
|
:isInsuranceSelected="isInsuranceSelected"
|
||||||
@vapsItemsSelected="vapsItemsSelectedAction"
|
@vapsItemsSelected="vapsItemsSelectedAction"
|
||||||
|
@servicePackageDiscountSelected="servicePackageDiscountSelectedAction"
|
||||||
:activePromos="lineItems.promos"
|
:activePromos="lineItems.promos"
|
||||||
v-on="{ 'buttonEvent.openModal': openModalAction }"
|
v-on="{ 'buttonEvent.openModal': openModalAction }"
|
||||||
validationRules="option-required"
|
validationRules="option-required"
|
||||||
|
|
@ -86,6 +87,7 @@ import contentGroupModal from "@/fmg-components/content-group-modal/content-grou
|
||||||
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||||
import afterpayModalBanner from "@/layouts/quote/afterpay-modal-banner/afterpay-modal-banner";
|
import afterpayModalBanner from "@/layouts/quote/afterpay-modal-banner/afterpay-modal-banner";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
import experimentMixin from "@/mixins/experiment-mixin.js";
|
||||||
import vehicleQuestionsMixin from "../../mixins/vehicle-questions-mixin";
|
import vehicleQuestionsMixin from "../../mixins/vehicle-questions-mixin";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
|
@ -105,7 +107,7 @@ import {
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||||
import promoModalQuestion from "@/fmg-components/promo-modal-question/promo-modal-question";
|
import promoModalQuestion from "@/fmg-components/promo-modal-question/promo-modal-question";
|
||||||
|
import { experimentSettings } from "@/constants/experiments";
|
||||||
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -155,11 +157,27 @@ export default {
|
||||||
const lineItems = deepClone(store.getters.order.lineItems);
|
const lineItems = deepClone(store.getters.order.lineItems);
|
||||||
lineItems.vaps = lineItems.vaps ?? [];
|
lineItems.vaps = lineItems.vaps ?? [];
|
||||||
const nullSafeGlassParts = lineItems.glassParts ?? [];
|
const nullSafeGlassParts = lineItems.glassParts ?? [];
|
||||||
|
const servicePackageDiscountSettingValue = experimentMixin.methods.getSettingValue(
|
||||||
|
experimentSettings.SERVICE_PACKAGE_DISCOUNT
|
||||||
|
);
|
||||||
|
const isServicePackageDiscount = servicePackageDiscountSettingValue === "True";
|
||||||
|
//Service package cash discount api call when experiment is active
|
||||||
|
var servicePackageDiscountPart = [];
|
||||||
|
if (isServicePackageDiscount) {
|
||||||
|
const servicePackageDiscountPartResponse =
|
||||||
|
await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
storeActions.CASH_SERVICE_PACKAGE_DISCOUNT,
|
||||||
|
null,
|
||||||
|
"quote"
|
||||||
|
);
|
||||||
|
servicePackageDiscountPart.push(servicePackageDiscountPartResponse.data);
|
||||||
|
}
|
||||||
const availableLineItems = [
|
const availableLineItems = [
|
||||||
resultMap.rainDefense,
|
resultMap.rainDefense,
|
||||||
...resultMap.supportingItems,
|
...resultMap.supportingItems,
|
||||||
...resultMap.wipers,
|
...resultMap.wipers,
|
||||||
...nullSafeGlassParts,
|
...nullSafeGlassParts,
|
||||||
|
...servicePackageDiscountPart,
|
||||||
];
|
];
|
||||||
|
|
||||||
const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
|
const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
|
@ -278,6 +296,9 @@ export default {
|
||||||
vapsItemsSelectedAction(vapsItemsSelected) {
|
vapsItemsSelectedAction(vapsItemsSelected) {
|
||||||
this.lineItems.vaps = vapsItemsSelected;
|
this.lineItems.vaps = vapsItemsSelected;
|
||||||
},
|
},
|
||||||
|
servicePackageDiscountSelectedAction(servicePackageDiscountSelected) {
|
||||||
|
this.lineItems.supportingItems = servicePackageDiscountSelected;
|
||||||
|
},
|
||||||
backButtonAction() {
|
backButtonAction() {
|
||||||
vehicleQuestionsMixin.methods.navigateBack(this);
|
vehicleQuestionsMixin.methods.navigateBack(this);
|
||||||
},
|
},
|
||||||
|
|
@ -315,7 +336,11 @@ export default {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
this.dispatchStoreAction(
|
||||||
|
this.storeActions.SAVE_SUPPORTING_ITEMS,
|
||||||
|
this.lineItems.supportingItems,
|
||||||
|
false
|
||||||
|
);
|
||||||
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.lineItems.vaps, false);
|
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.lineItems.vaps, false);
|
||||||
this.dispatchStoreAction(
|
this.dispatchStoreAction(
|
||||||
storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS,
|
storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,12 @@ import {
|
||||||
mockProcessedCmsContent,
|
mockProcessedCmsContent,
|
||||||
inputQuestionWidgetAnswers,
|
inputQuestionWidgetAnswers,
|
||||||
} from "./service-package-question-test-helper";
|
} from "./service-package-question-test-helper";
|
||||||
|
import {
|
||||||
|
containsLineItemWithPartType,
|
||||||
|
findLineItemsWithPartType,
|
||||||
|
} from "@/helpers/service-package-helper";
|
||||||
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
|
|
||||||
jest.mock("@/store", () => ({
|
jest.mock("@/store", () => ({
|
||||||
|
|
@ -45,7 +51,46 @@ describe("service-package-question.vue", () => {
|
||||||
partType: "RAIN DEFENSE",
|
partType: "RAIN DEFENSE",
|
||||||
price: 35.5,
|
price: 35.5,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
partNumber: "DISC CASHSAVE70",
|
||||||
|
description: null,
|
||||||
|
partType: "SERVICE PACKAGE DISCOUNT",
|
||||||
|
price: -70,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
lineItems: {
|
||||||
|
supportingItems: [
|
||||||
|
{
|
||||||
|
description: null,
|
||||||
|
id: "b0c68683-da85-46ba-bc86-2642bd9d5fdb",
|
||||||
|
kitPrice: 0,
|
||||||
|
laborAmount: 0,
|
||||||
|
partNumber: "RECYCLE FEE",
|
||||||
|
partType: "REPLACE FEE",
|
||||||
|
salesTax: null,
|
||||||
|
sellingPrice: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: null,
|
||||||
|
id: "5f205a07-3c08-4244-9935-76d63a7bcd19",
|
||||||
|
kitPrice: 0,
|
||||||
|
laborAmount: 395,
|
||||||
|
partNumber: "RECAL STATIC",
|
||||||
|
partType: "RECALIBRATION",
|
||||||
|
salesTax: null,
|
||||||
|
sellingPrice: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: null,
|
||||||
|
kitPrice: 0,
|
||||||
|
laborAmount: 0,
|
||||||
|
partNumber: "DISC CASHSAVE70",
|
||||||
|
partType: "SERVICE PACKAGE DISCOUNT",
|
||||||
|
salesTax: null,
|
||||||
|
sellingPrice: -70,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
activePromos: [],
|
activePromos: [],
|
||||||
};
|
};
|
||||||
const packageNameKey = "05_01_CSR_Quote_Standard_Repair";
|
const packageNameKey = "05_01_CSR_Quote_Standard_Repair";
|
||||||
|
|
@ -68,6 +113,44 @@ describe("service-package-question.vue", () => {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
it("should return price when there is discount", () => {
|
||||||
|
const wrapper = setupMocks({});
|
||||||
|
const partType = partTypeStrings.SERVICE_PACKAGE_DISCOUNT;
|
||||||
|
|
||||||
|
wrapper.vm.isServicePackageDiscountOnOrder = containsLineItemWithPartType(
|
||||||
|
partType,
|
||||||
|
mockProps.lineItems.supportingItems
|
||||||
|
);
|
||||||
|
const servicePackageDiscountLineItem = findLineItemsWithPartType(
|
||||||
|
partType,
|
||||||
|
mockProps.lineItems.supportingItems
|
||||||
|
);
|
||||||
|
wrapper.vm.getServicePackageDiscountPrice();
|
||||||
|
const price = baseMixin.methods.getTotalLineItemPrice(servicePackageDiscountLineItem[0]);
|
||||||
|
|
||||||
|
expect(Math.abs(price)).toEqual(70);
|
||||||
|
});
|
||||||
|
it("isServicePackageDiscountOnOrder returns true if it contains service package discount lineItems", () => {
|
||||||
|
// Arrange
|
||||||
|
const wrapper = setupMocks({});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.isServicePackageDiscountOnOrder).toBe(true);
|
||||||
|
});
|
||||||
|
it("servicePackageDiscountParts should returns service package discount lineItems", () => {
|
||||||
|
// Arrange
|
||||||
|
const wrapper = setupMocks({});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.servicePackageDiscountParts).toEqual([
|
||||||
|
{
|
||||||
|
partNumber: "DISC CASHSAVE70",
|
||||||
|
description: null,
|
||||||
|
partType: "SERVICE PACKAGE DISCOUNT",
|
||||||
|
price: -70,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
it("should have the correct insurance pricing text when insurance is selected", () => {
|
it("should have the correct insurance pricing text when insurance is selected", () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
mockProps.isInsuranceSelected = true;
|
mockProps.isInsuranceSelected = true;
|
||||||
|
|
|
||||||
|
|
@ -69,12 +69,34 @@ export default {
|
||||||
selectedPackageName(newValue) {
|
selectedPackageName(newValue) {
|
||||||
const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue);
|
const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue);
|
||||||
this.$emit("vapsItemsSelected", VapsProductsInSelectedPackage);
|
this.$emit("vapsItemsSelected", VapsProductsInSelectedPackage);
|
||||||
|
const servicePackageDiscountPartInSelectedPackage =
|
||||||
|
this.getServicePackageDiscountPartForSelectedPackage(newValue);
|
||||||
|
let supportingItems = this.supportingLineItems;
|
||||||
|
if (servicePackageDiscountPartInSelectedPackage?.length > 0) {
|
||||||
|
supportingItems?.push(servicePackageDiscountPartInSelectedPackage[0]);
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
supportingItems?.length > 0 &&
|
||||||
|
containsLineItemWithPartType(
|
||||||
|
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
|
||||||
|
supportingItems
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
supportingItems = supportingItems.filter(
|
||||||
|
(item) => item.partType !== partTypeStrings.SERVICE_PACKAGE_DISCOUNT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$emit("servicePackageDiscountSelected", supportingItems);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
nullSafeAvailableLineItems() {
|
nullSafeAvailableLineItems() {
|
||||||
return this.availableLineItems ?? [];
|
return this.availableLineItems ?? [];
|
||||||
},
|
},
|
||||||
|
supportingLineItems() {
|
||||||
|
return this.$store.getters.lineItems?.supportingItems;
|
||||||
|
},
|
||||||
servicePackageAnswers() {
|
servicePackageAnswers() {
|
||||||
const cmsWidgetName = this.isInsuranceSelected
|
const cmsWidgetName = this.isInsuranceSelected
|
||||||
? this.insuranceCmsWidgetName
|
? this.insuranceCmsWidgetName
|
||||||
|
|
@ -99,10 +121,16 @@ 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.getDiscountedPackagePriceString(answer.Name),
|
buttonAuxillaryCopy: this.getDiscountedPackagePriceString(
|
||||||
|
answer.Name,
|
||||||
|
this.isServicePackageDiscountOnOrder && answer.Text != ""
|
||||||
|
),
|
||||||
buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName),
|
buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName),
|
||||||
additionalButtonData: {
|
additionalButtonData: {
|
||||||
strikeThroughPrice: this.getPackagePriceString(answer.Name),
|
strikeThroughPrice: this.getPackagePriceString(answer.Name),
|
||||||
|
servicePackageDiscount:
|
||||||
|
this.isServicePackageDiscountOnOrder && answer.Text != "",
|
||||||
|
Text: answer.Text + this.getServicePackageDiscountPrice(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
return modifiedAnswers;
|
return modifiedAnswers;
|
||||||
|
|
@ -113,6 +141,12 @@ export default {
|
||||||
this.nullSafeAvailableLineItems
|
this.nullSafeAvailableLineItems
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
isServicePackageDiscountOnOrder() {
|
||||||
|
return containsLineItemWithPartType(
|
||||||
|
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
|
||||||
|
this.nullSafeAvailableLineItems
|
||||||
|
);
|
||||||
|
},
|
||||||
frontWipersApplicableForTierTwo() {
|
frontWipersApplicableForTierTwo() {
|
||||||
return shouldFrontWipersBeAvailable(
|
return shouldFrontWipersBeAvailable(
|
||||||
this.glassToReplace,
|
this.glassToReplace,
|
||||||
|
|
@ -159,6 +193,12 @@ export default {
|
||||||
isRepair() {
|
isRepair() {
|
||||||
return this.$store.getters.order.damage.isRepair;
|
return this.$store.getters.order.damage.isRepair;
|
||||||
},
|
},
|
||||||
|
servicePackageDiscountParts() {
|
||||||
|
return findLineItemsWithPartType(
|
||||||
|
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
|
||||||
|
this.nullSafeAvailableLineItems
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
processIfStatements,
|
processIfStatements,
|
||||||
|
|
@ -178,21 +218,35 @@ export default {
|
||||||
},
|
},
|
||||||
getPackagePriceString(packageName) {
|
getPackagePriceString(packageName) {
|
||||||
const formattedPriceFloat = parseFloat(
|
const formattedPriceFloat = parseFloat(
|
||||||
this.getPackagePrice(packageName, { discountedPrice: false })
|
this.getPackagePrice(packageName, {
|
||||||
|
discountedPrice: false,
|
||||||
|
servicePackageDiscount: false,
|
||||||
|
})
|
||||||
).toFixed(2);
|
).toFixed(2);
|
||||||
return "$" + formattedPriceFloat;
|
return "$" + formattedPriceFloat;
|
||||||
},
|
},
|
||||||
getDiscountedPackagePriceString(packageName) {
|
getDiscountedPackagePriceString(packageName, servicePackageDiscount) {
|
||||||
const formattedPriceFloat = parseFloat(
|
const formattedPriceFloat = parseFloat(
|
||||||
this.getPackagePrice(packageName, { discountedPrice: true })
|
this.getPackagePrice(packageName, { discountedPrice: true, servicePackageDiscount })
|
||||||
).toFixed(2);
|
).toFixed(2);
|
||||||
return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat;
|
return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat;
|
||||||
},
|
},
|
||||||
getPackagePrice(packageName, { discountedPrice = false }) {
|
getPackagePrice(packageName, { discountedPrice = false, servicePackageDiscount = false }) {
|
||||||
const lineItemsToPrice = [...this.nullSafeAvailableLineItems];
|
var lineItemsToPrice = [...this.nullSafeAvailableLineItems];
|
||||||
|
|
||||||
|
//remove service package discount part
|
||||||
|
if (this.isServicePackageDiscountOnOrder) {
|
||||||
|
lineItemsToPrice = this.nullSafeAvailableLineItems.filter((item) => {
|
||||||
|
return item.partType != this.servicePackageDiscountParts[0].partType;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (discountedPrice) {
|
if (discountedPrice) {
|
||||||
lineItemsToPrice.push(...removeVapsPromosFromPromoArray(this.activePromos));
|
lineItemsToPrice.push(...removeVapsPromosFromPromoArray(this.activePromos));
|
||||||
}
|
}
|
||||||
|
if (servicePackageDiscount) {
|
||||||
|
lineItemsToPrice.push(...this.servicePackageDiscountParts);
|
||||||
|
}
|
||||||
let priceFloat = this.isInsuranceSelected
|
let priceFloat = this.isInsuranceSelected
|
||||||
? 0
|
? 0
|
||||||
: baseMixin.methods.getTierOnePackagePrice(
|
: baseMixin.methods.getTierOnePackagePrice(
|
||||||
|
|
@ -203,9 +257,17 @@ export default {
|
||||||
|
|
||||||
return priceFloat;
|
return priceFloat;
|
||||||
},
|
},
|
||||||
|
getServicePackageDiscountPrice() {
|
||||||
|
if (this.isServicePackageDiscountOnOrder) {
|
||||||
|
let price = 0;
|
||||||
|
price += baseMixin.methods.getTotalLineItemPrice(
|
||||||
|
this.servicePackageDiscountParts[0]
|
||||||
|
);
|
||||||
|
return Math.abs(price);
|
||||||
|
}
|
||||||
|
},
|
||||||
getVapsPrice(packageName, applyPromoDiscounts = false) {
|
getVapsPrice(packageName, applyPromoDiscounts = false) {
|
||||||
const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName);
|
const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName);
|
||||||
|
|
||||||
let price = 0;
|
let price = 0;
|
||||||
|
|
||||||
vapsItems.forEach((item) => {
|
vapsItems.forEach((item) => {
|
||||||
|
|
@ -261,6 +323,14 @@ export default {
|
||||||
|
|
||||||
return vapsLineItemsForSelectedPackage;
|
return vapsLineItemsForSelectedPackage;
|
||||||
},
|
},
|
||||||
|
getServicePackageDiscountPartForSelectedPackage(packageName) {
|
||||||
|
const selectedPackage = this.servicePackageAnswers.filter(
|
||||||
|
(item) => item.value === packageName
|
||||||
|
);
|
||||||
|
if (selectedPackage?.[0]?.additionalButtonData?.servicePackageDiscount) {
|
||||||
|
return this.servicePackageDiscountParts;
|
||||||
|
} else return [];
|
||||||
|
},
|
||||||
combineLineItemsWithoutDuplicates(lineItemsOne, lineItemsTwo) {
|
combineLineItemsWithoutDuplicates(lineItemsOne, lineItemsTwo) {
|
||||||
const combinedLineItemArray = [...lineItemsTwo];
|
const combinedLineItemArray = [...lineItemsTwo];
|
||||||
lineItemsOne.forEach((lineItemOne) => {
|
lineItemsOne.forEach((lineItemOne) => {
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,6 @@ describe("service-package-radio.vue", () => {
|
||||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps["buttonLabel"]));
|
expect(outputHtml).toEqual(expect.stringContaining(mockProps["buttonLabel"]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should include buttonLabelAuxillaryCopy in html", async () => {
|
|
||||||
// Arrange
|
|
||||||
let { wrapper } = setupMocks({
|
|
||||||
mountOptionsMockData: {
|
|
||||||
propsData: mockProps,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const outputHtml = wrapper.html();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(outputHtml).toEqual(expect.stringContaining(mockProps["buttonLabelAuxillaryCopy"]));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should include buttonLabelSubCopy in html", async () => {
|
it("Should include buttonLabelSubCopy in html", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
let { wrapper } = setupMocks({
|
let { wrapper } = setupMocks({
|
||||||
|
|
@ -123,7 +108,11 @@ const mockProps = {
|
||||||
"<ul><li>buttonBodyCopy test copy</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>",
|
"<ul><li>buttonBodyCopy test copy</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>",
|
||||||
buttonFooterCopy: "buttonFooterCopy test copy",
|
buttonFooterCopy: "buttonFooterCopy test copy",
|
||||||
buttonAuxillaryCopy: "buttonAuxillaryCopy test copy",
|
buttonAuxillaryCopy: "buttonAuxillaryCopy test copy",
|
||||||
additionalButtonData: { strikeThroughPrice: "strikeThroughPrice test copy" },
|
additionalButtonData: {
|
||||||
|
strikeThroughPrice: "strikeThroughPrice test copy",
|
||||||
|
servicePackageDiscount: true,
|
||||||
|
Text: "Special save",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function setupMocks({ mountOptionsMockData = {} }) {
|
function setupMocks({ mountOptionsMockData = {} }) {
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,51 @@
|
||||||
<template>
|
<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">
|
<baseInputButton v-bind="$props" @buttonClicked="handleAnswerChange" v-model="selectedValue">
|
||||||
<div
|
<div
|
||||||
class="package-label"
|
class="package-label"
|
||||||
:class="[this.buttonLabelSubCopy ? 'has-subheader' : '']"
|
:class="[
|
||||||
|
this.buttonLabelSubCopy ? 'has-subheader' : '',
|
||||||
|
this.additionalButtonData.servicePackageDiscount ? 'has-text' : '',
|
||||||
|
]"
|
||||||
for="testradio">
|
for="testradio">
|
||||||
<div class="package-specs">
|
<div class="package-specs">
|
||||||
<p class="m-0">
|
<div v-if="this.additionalButtonData.servicePackageDiscount" class="row">
|
||||||
<span v-html="this.buttonLabel"></span>
|
<div class="col md-6">
|
||||||
<span class="pricing-info">
|
<p class="m-0">
|
||||||
<span
|
<span v-html="this.buttonLabel"></span>
|
||||||
class="strikethrough-price"
|
</p>
|
||||||
|
<p
|
||||||
|
class="sub-label m-0"
|
||||||
|
v-if="this.buttonLabelSubCopy"
|
||||||
|
v-html="this.buttonLabelSubCopy"></p>
|
||||||
|
</div>
|
||||||
|
<span class="col md-6 service-package-discount">
|
||||||
|
<div
|
||||||
|
class="strikethrough-discount-price"
|
||||||
v-if="shouldDisplayStrikeThroughPrice"
|
v-if="shouldDisplayStrikeThroughPrice"
|
||||||
v-html="this.additionalButtonData.strikeThroughPrice"></span>
|
v-html="this.additionalButtonData.strikeThroughPrice"></div>
|
||||||
<span v-html="this.buttonAuxillaryCopy"></span>*
|
<div class="discount-price" v-html="this.buttonAuxillaryCopy"></div>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</div>
|
||||||
<p
|
<div v-else>
|
||||||
class="sub-label m-0"
|
<p class="m-0">
|
||||||
v-if="this.buttonLabelSubCopy"
|
<span v-html="this.buttonLabel"></span>
|
||||||
v-html="this.buttonLabelSubCopy"></p>
|
<span class="pricing-info">
|
||||||
|
<span
|
||||||
|
class="strikethrough-price"
|
||||||
|
v-if="shouldDisplayStrikeThroughPrice"
|
||||||
|
v-html="this.additionalButtonData.strikeThroughPrice"></span>
|
||||||
|
<span v-html="this.buttonAuxillaryCopy"></span>*
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="sub-label m-0"
|
||||||
|
v-if="this.buttonLabelSubCopy"
|
||||||
|
v-html="this.buttonLabelSubCopy"></p>
|
||||||
|
</div>
|
||||||
<div class="hide-when-closed">
|
<div class="hide-when-closed">
|
||||||
<!-- Parse the body text containing <ul> with logic -->
|
<!-- Parse the body text containing <ul> with logic -->
|
||||||
<ul>
|
<ul>
|
||||||
|
|
@ -109,6 +136,18 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
.discount-text {
|
||||||
|
line-height: 36px;
|
||||||
|
display: flex;
|
||||||
|
border-top-right-radius: 0.5rem;
|
||||||
|
border-top-left-radius: 0.5rem;
|
||||||
|
background-color: #469d2a;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 5px;
|
||||||
|
width: 100%;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
.package-main {
|
.package-main {
|
||||||
.package-wrapper {
|
.package-wrapper {
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
|
|
@ -139,6 +178,10 @@ export default {
|
||||||
&.has-subheader {
|
&.has-subheader {
|
||||||
min-height: 80px;
|
min-height: 80px;
|
||||||
}
|
}
|
||||||
|
&.has-text {
|
||||||
|
border-radius: 0 0 0.5rem 0.5rem;
|
||||||
|
border: 1px solid #469d2a !important;
|
||||||
|
}
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
content: "";
|
content: "";
|
||||||
|
|
@ -246,6 +289,28 @@ export default {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
span {
|
||||||
|
&.service-package-discount {
|
||||||
|
color: #469d2a;
|
||||||
|
text-align: end;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 13px;
|
||||||
|
div.strikethrough-discount-price {
|
||||||
|
text-decoration: line-through;
|
||||||
|
margin-right: 0;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
color: $gray-550;
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
div.discount-price {
|
||||||
|
color: #469d2a;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ul {
|
ul {
|
||||||
margin: 1rem 0 0 -15px;
|
margin: 1rem 0 0 -15px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
||||||
|
|
@ -1422,6 +1422,26 @@ export const actions = {
|
||||||
pageNameToLog: pageNameToLog,
|
pageNameToLog: pageNameToLog,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
cashServicePackageDiscount(context, { pageNameToLog }) {
|
||||||
|
const damage = context.getters.damage;
|
||||||
|
const damageType = damage.isRepair ? "Repair" : "Replace";
|
||||||
|
const glassPieces = convertGlassPieceNamingForApi(damage.glassToReplace);
|
||||||
|
|
||||||
|
return globalMethods
|
||||||
|
.callHttpClient({
|
||||||
|
method: endpoints.CashServicePackageDiscount.method,
|
||||||
|
endpoint: endpoints.CashServicePackageDiscount.url,
|
||||||
|
payload: {
|
||||||
|
glassPieces: glassPieces,
|
||||||
|
damageType: damageType,
|
||||||
|
},
|
||||||
|
logApiCall: true,
|
||||||
|
pageNameToLog: pageNameToLog,
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getServiceabilityDetails(context, { payload: { serviceZipCode }, pageNameToLog }) {
|
getServiceabilityDetails(context, { payload: { serviceZipCode }, pageNameToLog }) {
|
||||||
const lineItemsWithOnlyPartNumbers = context.getters.order.lineItems.supportingItems?.map(
|
const lineItemsWithOnlyPartNumbers = context.getters.order.lineItems.supportingItems?.map(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue