From 4b156612acc7bf0e264db9a514f07c04e56ced6d Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 4 Nov 2025 15:12:14 -0500 Subject: [PATCH] Change to quote page discounts --- src/constants/cart-item-categories.js | 2 +- src/constants/cart-item-types.js | 2 +- src/constants/part-type-strings.js | 1 + src/constants/quote-page-discounts.js | 80 +++++++++++++ .../service-package-radio-for-afterpay.vue | 4 +- .../service-package-radio.vue | 9 +- src/fmg-components/cart/cart.vue | 79 ++++++------- src/layouts/quote/quote.spec.js | 2 +- src/layouts/quote/quote.vue | 104 ++++++++++------- .../service-package-question.spec.js | 53 ++++----- .../service-package-question.vue | 110 ++++++++---------- .../service-package-radio.vue | 7 +- src/mixins/base-mixin.js | 4 +- 13 files changed, 260 insertions(+), 197 deletions(-) create mode 100644 src/constants/quote-page-discounts.js diff --git a/src/constants/cart-item-categories.js b/src/constants/cart-item-categories.js index 6bbb960b9..5c8faafcf 100644 --- a/src/constants/cart-item-categories.js +++ b/src/constants/cart-item-categories.js @@ -3,7 +3,7 @@ const cartItemCategories = { GLASS_PARTS: "glassParts", SUPPORTING_ITEMS: "supportingItems", PROMOS: "promos", - SERVICE_PACKAGE_DISCOUNT: "servicePackageDiscount", + QUOTE_PAGE_DISCOUNT: "quotePageDiscount", }; export { cartItemCategories }; diff --git a/src/constants/cart-item-types.js b/src/constants/cart-item-types.js index 0bb418d43..8f70aeaed 100644 --- a/src/constants/cart-item-types.js +++ b/src/constants/cart-item-types.js @@ -10,7 +10,7 @@ const cartItemTypes = { PROMOS: "PROMOS", EARLY_BIRD: "EARLY BIRD", SUPPLIES_REPAIR: "SUPPLIES-REPAIR", - SERVICE_PACKAGE_DISCOUNT: "SERVICE PACKAGE DISCOUNT", + QUOTE_PAGE_DISCOUNT: "QUOTE PAGE DISCOUNT", DONATION: "DONATION", }; diff --git a/src/constants/part-type-strings.js b/src/constants/part-type-strings.js index 741132e28..17b96d2fb 100644 --- a/src/constants/part-type-strings.js +++ b/src/constants/part-type-strings.js @@ -10,6 +10,7 @@ const partTypeStrings = { REPAIR_FEE: "REPAIR FEE", EARLY_BIRD: "EARLY BIRD", SERVICE_PACKAGE_DISCOUNT: "SERVICE PACKAGE DISCOUNT", + QUOTE_PAGE_DISCOUNT: "QUOTE PAGE DISCOUNT", DONATION: "DONATION", }; diff --git a/src/constants/quote-page-discounts.js b/src/constants/quote-page-discounts.js new file mode 100644 index 000000000..2dd32d915 --- /dev/null +++ b/src/constants/quote-page-discounts.js @@ -0,0 +1,80 @@ +import { packageNames } from "./package-names"; +import { partTypeStrings } from "./part-type-strings"; + +export const quotePageDiscountTable = [ + // Repair + { + name: "Repair Glass Only", + experimentCode: "Show_GlassOnly_Repair_Discount", + partNumber: "GL RPR CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "GLASS RPR GEOTARGET DISC", + packageLevel: packageNames.TIER_ONE, + }, + { + name: "Repair Standard", + experimentCode: "Show_Standard_Repair_Discount", + partNumber: "STD RPR CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "STD RPR GEOTARGET DISC", + packageLevel: packageNames.TIER_TWO, + }, + { + name: "Repair Premium", + experimentCode: "Show_Premium_Repair_Discount", + partNumber: "PRM RPR CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "PREM RPR GEOTARGET DISC", + packageLevel: packageNames.TIER_THREE, + }, + // Replace - No recal + { + name: "Replace Glass Only", + experimentCode: "Show_GlassOnly_Replace_Discount", + partNumber: "GL RPL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "GLASS RPL GEOTARGET DISC", + packageLevel: packageNames.TIER_ONE, + }, + { + name: "Replace Standard", + experimentCode: "Show_Standard_Replace_Discount", + partNumber: "STD RPL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "STD RPL GEOTARGET DISC", + packageLevel: packageNames.TIER_TWO, + }, + { + name: "Replace Premium", + experimentCode: "Show_Premium_Replace_Discount", + partNumber: "PRM RPL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "PREM RPL GEOTARGET DISC", + packageLevel: packageNames.TIER_THREE, + }, + // Replace - with recal + { + name: "Recal Glass Only", + experimentCode: "Show_GlassOnly_Recal_Discount", + partNumber: "GL RCL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "GLASS RCL GEOTARGET DISC", + packageLevel: packageNames.TIER_ONE, + }, + { + name: "Recal Standard", + experimentCode: "Show_Standard_Recal_Discount", + partNumber: "STD RCL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "STD RCL GEOTARGET DISC", + packageLevel: packageNames.TIER_TWO, + }, + { + name: "Recal Premium", + experimentCode: "Show_Premium_Recal_Discount", + partNumber: "PRM RCL CSH PKG", + partType: partTypeStrings.QUOTE_PAGE_DISCOUNT, + description: "PREM RCL GEOTARGET DISC", + packageLevel: packageNames.TIER_THREE, + }, +]; diff --git a/src/experiment-components/service-package-radio-for-afterpay.vue b/src/experiment-components/service-package-radio-for-afterpay.vue index 2e746e4f2..7f7e91084 100644 --- a/src/experiment-components/service-package-radio-for-afterpay.vue +++ b/src/experiment-components/service-package-radio-for-afterpay.vue @@ -145,9 +145,7 @@ export default { return "$" + decimalPrice.toFixed(2); }, hasPackageDiscount() { - return ( - this.additionalButtonData.servicePackageDiscount && this.additionalButtonData.Text - ); + return this.additionalButtonData.hasDiscount && this.additionalButtonData.Text; }, }, }; diff --git a/src/experiment-components/service-package-radio.vue b/src/experiment-components/service-package-radio.vue index ee7e12712..a116fecd8 100644 --- a/src/experiment-components/service-package-radio.vue +++ b/src/experiment-components/service-package-radio.vue @@ -4,11 +4,11 @@ class="package-label pricing-by-day-pkg-lbl" :class="[ this.buttonLabelSubCopy ? 'has-subheader' : '', - !this.additionalButtonData.servicePackageDiscount ? 'adjust-top' : '', + !this.additionalButtonData.hasDiscount ? 'adjust-top' : '', ]" for="testradio">
-
+

@@ -84,10 +84,7 @@

diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index d1bd2a939..e890e53cc 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -190,6 +190,7 @@ import { cartItemCategories } from "@/constants/cart-item-categories"; import { cartItemTypes } from "@/constants/cart-item-types"; import { coverageStatus, cartItemTypesCoveredByInsurance } from "@/constants/insurance"; import { experimentSettings } from "@/constants/experiments"; +import { quotePageDiscountTable } from "@/constants/quote-page-discounts"; export default { name: "cart", @@ -256,11 +257,11 @@ export default { return subTotal; }, - getServicePackageDiscount() { - const servicePackageDiscountLineItems = this.servicePackageDiscountCartItem; + getQuotePageDiscount() { + const quotePageDiscountLineItems = this.quotePageDiscountCartItem; let subTotal = 0; - subTotal += servicePackageDiscountLineItems?.subTotal ?? 0; + subTotal += quotePageDiscountLineItems?.subTotal ?? 0; return subTotal; }, getVapsCartItemsForSelectedPackage(packageName) { @@ -303,7 +304,8 @@ export default { getLineItemAmount(amount, useVerifyingText, category) { if (useVerifyingText) return this.verifyingCoverageText; - return category == "promos" || category == "servicePackageDiscount" + return category == cartItemCategories.PROMOS || + category == cartItemCategories.QUOTE_PAGE_DISCOUNT ? "(" + this.currencyFormatter.format(amount * -1) + ")" : this.currencyFormatter.format(amount); }, @@ -316,16 +318,21 @@ export default { if (category == cartItemCategories.VAPS || category == cartItemCategories.PROMOS) { this.saveVaps(this.lineItems); // Check if service package discount should be removed after vaps change - if ( - this.servicePackageDiscountCartItem && - this.discountPackageNames != this.packageLevel - ) { - this.lineItems.supportingItems = this.lineItems.supportingItems.filter( - (lineItemsToKeep) => - lineItemsToKeep.cartItemType != - this.servicePackageDiscountCartItem.cartItemType + if (this.quotePageDiscountCartItem) { + const existingLineItem = this.quotePageDiscountCartItem.lineItems.at(0); + const discountInfo = quotePageDiscountTable.find( + (info) => info.partNumber === existingLineItem?.partNumber ); - shouldSaveSupportingItems = true; + const packageLevelForDiscount = discountInfo?.packageLevel; + + if (this.packageLevel !== packageLevelForDiscount) { + this.lineItems.supportingItems = this.lineItems.supportingItems.filter( + (lineItemsToKeep) => + lineItemsToKeep.cartItemType != + this.quotePageDiscountCartItem.cartItemType + ); + shouldSaveSupportingItems = true; + } } } if (shouldSaveSupportingItems) { @@ -483,8 +490,8 @@ export default { cartItems.push(this.mobileFeeCartItem); } - if (this.servicePackageDiscountCartItem) { - cartItems.push(this.servicePackageDiscountCartItem); + if (this.quotePageDiscountCartItem) { + cartItems.push(this.quotePageDiscountCartItem); } if (this.premiumAppointmentDiscountCartItem) { @@ -500,12 +507,6 @@ export default { return cartItems; }, }, - discountPackageNames() { - const discountServicePackage = experimentMixin.methods.getSettingValue( - experimentSettings.PROMO_ON_PACKAGE - ); - return getDiscountedPackageName(discountServicePackage); - }, servicePackageTitleWidget() { const servicePackageNames = this.getCmsContent( this.servicePackageOptionsCmsName, @@ -550,8 +551,8 @@ export default { } packagePrice += this.getVapsPrice(this.packageLevel); - if (this.servicePackageDiscountCartItem) { - packagePrice -= this.getServicePackageDiscount(); + if (this.quotePageDiscountCartItem) { + packagePrice -= this.getQuotePageDiscount(); } return packagePrice; @@ -928,25 +929,25 @@ export default { } return cartItem; }, - servicePackageDiscountCartItemName() { + quotePageDiscountCartItemName() { return this.getCmsContent("ServicePackageDiscountTextWidget", "Text"); }, - servicePackageDiscountCartItem() { + quotePageDiscountCartItem() { let cartItem = null; - const servicePackageDiscountLineItem = this.supportingItems.find( - (lineItem) => lineItem.partType == partTypeStrings.SERVICE_PACKAGE_DISCOUNT + const quotePageDiscountLineItem = this.supportingItems.find( + (lineItem) => lineItem.partType == partTypeStrings.QUOTE_PAGE_DISCOUNT ); - if (servicePackageDiscountLineItem) { + if (quotePageDiscountLineItem) { cartItem = { name: - this.servicePackageDiscountCartItemName + + this.quotePageDiscountCartItemName + Math.abs( - baseMixin.methods.getTotalLineItemPrice(servicePackageDiscountLineItem) + baseMixin.methods.getTotalLineItemPrice(quotePageDiscountLineItem) ), - category: cartItemCategories.SERVICE_PACKAGE_DISCOUNT, - cartItemType: cartItemTypes.SERVICE_PACKAGE_DISCOUNT, + category: cartItemCategories.QUOTE_PAGE_DISCOUNT, + cartItemType: cartItemTypes.QUOTE_PAGE_DISCOUNT, isDisplayed: true, isRemovable: false, subTotal: 0, @@ -955,15 +956,15 @@ export default { isCoveredByInsurance: false, }; - servicePackageDiscountLineItem.cartItemType = cartItem.cartItemType; - cartItem.lineItems.push(servicePackageDiscountLineItem); + quotePageDiscountLineItem.cartItemType = cartItem.cartItemType; + cartItem.lineItems.push(quotePageDiscountLineItem); cartItem.subTotal += - (servicePackageDiscountLineItem.kitPrice ?? 0) + - (servicePackageDiscountLineItem.laborAmount ?? 0) + - (servicePackageDiscountLineItem.sellingPrice ?? 0); + (quotePageDiscountLineItem.kitPrice ?? 0) + + (quotePageDiscountLineItem.laborAmount ?? 0) + + (quotePageDiscountLineItem.sellingPrice ?? 0); - cartItem.salesTax += servicePackageDiscountLineItem.salesTax ?? 0; + cartItem.salesTax += quotePageDiscountLineItem.salesTax ?? 0; } return cartItem; @@ -972,7 +973,7 @@ export default { let cartItem = null; const otherSupportingItems = this.supportingItems.filter((item) => { - return item.partType != partTypeStrings.SERVICE_PACKAGE_DISCOUNT; + return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; }); // Don't include fees they are part of the package total let otherSupportingItemsLineItems = diff --git a/src/layouts/quote/quote.spec.js b/src/layouts/quote/quote.spec.js index aea32211e..5d9f3bacb 100644 --- a/src/layouts/quote/quote.spec.js +++ b/src/layouts/quote/quote.spec.js @@ -82,7 +82,7 @@ jest.mock("@/mixins/base-mixin", () => ({ filterOutFees(items) { return null; }, - filterOutServicePackageDiscountPart(items) { + filterOutQuotePageDiscountPart(items) { return null; }, isFormValid(form) { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 8bab96d5f..78d6c24ff 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -31,10 +31,11 @@ :isRecalibrationOnOrder="isRecalibrationOnOrder" :shouldHideRecalibration="shouldHideRecalibration" @vapsItemsSelected="vapsItemsSelectedAction" - @servicePackageDiscountSelected="servicePackageDiscountSelectedAction" + @quotePageDiscountSelected="quotePageDiscountSelectedAction" @currentNumberOfPackages="currentNumberOfPackagesAction" :servicePackage="servicePackage" :activePromos="lineItems.promos" + :availableQuotePageDiscounts="quoteDiscountPartsInfo" v-on="{ 'buttonEvent.openModal': openModalAction }" validationRules="option-required" isRequired /> @@ -176,6 +177,7 @@ import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stas import { storeMutations } from "@/constants/store-mutations"; import { debugLog } from "@/helpers/debug-log-helper"; import { savePageData } from "@/router/methods/helpers/save-page-data"; +import { quotePageDiscountTable } from "../../constants/quote-page-discounts"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); @@ -186,6 +188,14 @@ const ACCEPTED_QUOTE_TYPES = { INSURANCE: "insurance", }; +function getAvailableQuotePageDiscounts() { + const activeDiscounts = quotePageDiscountTable?.filter((discountEntry) => + experimentMixin?.methods?.hasSettingEqualTo(discountEntry?.experimentCode, "true") + ); + + return activeDiscounts ?? []; +} + export default { name: "quote", async beforeRouteEnter(to, from, next) { @@ -302,29 +312,22 @@ export default { const lineItems = deepClone(store.getters.order.lineItems); lineItems.vaps = lineItems.vaps ?? []; 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.GET_SERVICE_PACKAGE_DISCOUNT_PART, - null, - "quote" - ); - if (servicePackageDiscountPartResponse.data) { - servicePackageDiscountPart.push(servicePackageDiscountPartResponse.data); - } - } + + const quotePageDiscountPartsInfo = getAvailableQuotePageDiscounts(); + + const quotePageDiscountParts = quotePageDiscountPartsInfo.map((partInfo) => ({ + partNumber: partInfo.partNumber, + partType: partInfo.partType, + description: partInfo.description, + isInsurable: null, + })); + const availableLineItems = [ resultMap.rainRepel, ...resultMap.supportingItems, ...resultMap.wipers, ...nullSafeGlassParts, - ...servicePackageDiscountPart, + ...quotePageDiscountParts, ]; // When calling pricing from the quote page, always use the cash parent account but save the existing one in case it's unverified insurance navigating backwards @@ -351,7 +354,7 @@ export default { false ); - // This will remove any servicePackageDiscount item from lineItems.supportingItems + // This will remove any discount item from lineItems.supportingItems baseMixin.methods.dispatchStoreAction( storeActions.SAVE_SUPPORTING_ITEMS, resultMap.supportingItems, @@ -453,10 +456,9 @@ export default { ) : baseMixin.methods.filterOutFees(availableLineItems); - const lineItemsNoDiscount = - baseMixin.methods.filterOutServicePackageDiscountPart( - lineItemsForCalculatingPrice - ); + const lineItemsNoDiscount = baseMixin.methods.filterOutQuotePageDiscountPart( + lineItemsForCalculatingPrice + ); if (isInsuranceFromQueryString != null) { if (isInsuranceFromQueryString.toLowerCase() === "true") { @@ -580,17 +582,8 @@ export default { isRecalibrationOnOrder() { return store.getters.isRecalibrationOnOrder; }, - isServicePackageDiscountOnOrder() { - return containsLineItemWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - this.availableLineItems - ); - }, - servicePackageDiscountParts() { - return findLineItemsWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - this.availableLineItems - ); + isQuotePageDiscountOnOrder() { + return this.quotePageDiscountPartsInfo?.length > 0; }, shouldHideRecalibration() { return ( @@ -619,6 +612,23 @@ export default { thresholdAmount && (thresholdAmount = parseInt(thresholdAmount)); return thresholdAmount; }, + quoteDiscountPartsInfo() { + const defs = getAvailableQuotePageDiscounts(); + const withPrices = defs + .map((def) => { + const match = this.availableLineItems?.find?.( + (pricedItem) => pricedItem.partNumber === def.partNumber + ); + + return { + packageLevel: def.packageLevel, + item: match, + }; + }) + .filter((result) => result.item); + + return withPrices; + }, }, methods: { getColCount() { @@ -662,7 +672,7 @@ export default { vapsItemsSelectedAction(vapsItemsSelected) { this.lineItems.vaps = vapsItemsSelected; }, - servicePackageDiscountSelectedAction(supportingItemsSelected) { + quotePageDiscountSelectedAction(supportingItemsSelected) { this.lineItems.supportingItems = supportingItemsSelected; }, backButtonAction() { @@ -724,10 +734,10 @@ export default { false ); } - if (this.isInsuranceSelected && this.isServicePackageDiscountOnOrder) { + if (this.isInsuranceSelected && this.isQuotePageDiscountOnOrder) { let supportingItems = this.lineItems.supportingItems; supportingItems = supportingItems.filter((item) => { - return item.partType != this.servicePackageDiscountParts[0].partType; + return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; }); this.dispatchStoreAction( this.storeActions.SAVE_SUPPORTING_ITEMS, @@ -813,19 +823,23 @@ export default { lineItemsToPrice = baseMixin.methods.filterOutRecalibration(lineItemsToPrice); } - if (this.isServicePackageDiscountOnOrder) { + if (this.isQuotePageDiscountOnOrder) { lineItemsToPrice = lineItemsToPrice?.filter((item) => { - return ( - item.partType != this.servicePackageDiscountParts[0].partType - ); + return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; }); } let price = 0; if ( - tier.additionalButtonData?.servicePackageDiscount && - this.isServicePackageDiscountOnOrder + tier.additionalButtonData?.hasDiscount && + this.isQuotePageDiscountOnOrder ) { - lineItemsToPrice.push(...this.servicePackageDiscountParts); + const parts = this.quoteDiscountPartsInfo; + const matchPart = parts.find( + (discountInfo) => discountInfo.packageLevel === tier + ); + if (matchPart) { + lineItemsToPrice.push(matchPart); + } } price += baseMixin.methods.getTierOnePackagePrice( baseMixin.methods.filterOutFees(lineItemsToPrice) diff --git a/src/layouts/quote/service-package-question/service-package-question.spec.js b/src/layouts/quote/service-package-question/service-package-question.spec.js index 523c0edce..a44dc463c 100644 --- a/src/layouts/quote/service-package-question/service-package-question.spec.js +++ b/src/layouts/quote/service-package-question/service-package-question.spec.js @@ -14,6 +14,7 @@ import { experimentSettings } from "@/constants/experiments"; import baseMixin from "@/mixins/base-mixin.js"; import { partTypeStrings } from "@/constants/part-type-strings"; import { nextTick } from "vue"; +import { packageNames } from "../../../constants/package-names"; jest.mock("@/store", () => ({ commit: jest.fn(), @@ -73,9 +74,9 @@ describe("service-package-question.vue", () => { price: 35.5, }, { - partNumber: "DISC CASHSAVE70", + partNumber: "PRM RCL CSH PKG", description: null, - partType: "SERVICE PACKAGE DISCOUNT", + partType: "QUOTE PAGE DISCOUNT", price: -70, }, ], @@ -105,13 +106,27 @@ describe("service-package-question.vue", () => { description: null, kitPrice: 0, laborAmount: 0, - partNumber: "DISC CASHSAVE70", - partType: "SERVICE PACKAGE DISCOUNT", + partNumber: "PRM RCL CSH PKG", + partType: "QUOTE PAGE DISCOUNT", salesTax: null, sellingPrice: -70, }, ], }, + availableQuotePageDiscounts: [ + { + packageLevel: packageNames.TIER_THREE, + item: { + description: null, + kitPrice: 0, + laborAmount: 0, + partNumber: "PRM RCL CSH PKG", + partType: "QUOTE PAGE DISCOUNT", + salesTax: null, + sellingPrice: -70, + }, + }, + ], activePromos: [], }; const packageNameKey = "05_01_CSR_Quote_Standard_Repair"; @@ -136,41 +151,17 @@ 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]); + const price = wrapper.vm.getDiscountPrice(packageNames.TIER_THREE); expect(Math.abs(price)).toEqual(70); }); - it("isServicePackageDiscountOnOrder returns true if it contains service package discount lineItems", () => { + it("isDiscountOnOrder returns true if it contains quote 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, - }, - ]); + expect(wrapper.vm.isDiscountOnOrder).toBe(true); }); it("should have the correct insurance pricing text when insurance is selected", () => { // Arrange diff --git a/src/layouts/quote/service-package-question/service-package-question.vue b/src/layouts/quote/service-package-question/service-package-question.vue index d1a99da08..e45147295 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -60,6 +60,7 @@ export default { servicePackage: null, isRecalibrationOnOrder: Boolean, shouldHideRecalibration: Boolean, + availableQuotePageDiscounts: null, }, data() { return { @@ -85,27 +86,18 @@ export default { selectedPackageName(newValue) { const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue); this.$emit("vapsItemsSelected", VapsProductsInSelectedPackage); - const servicePackageDiscountPartInSelectedPackage = - this.getServicePackageDiscountPartForSelectedPackage(newValue); + const discountPartInSelectedPackage = this.getDiscountPartForSelectedPackage(newValue); let supportingItems = this.supportingLineItems; - if ( - containsLineItemWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - supportingItems - ) - ) { - supportingItems = supportingItems.filter( - (item) => item.partType !== partTypeStrings.SERVICE_PACKAGE_DISCOUNT - ); - } - if ( - servicePackageDiscountPartInSelectedPackage?.length > 0 && - supportingItems != null - ) { - supportingItems.push(servicePackageDiscountPartInSelectedPackage[0]); + + supportingItems = supportingItems.filter( + (item) => item.partType !== partTypeStrings.QUOTE_PAGE_DISCOUNT + ); + + if (discountPartInSelectedPackage) { + supportingItems.push(discountPartInSelectedPackage); } - this.$emit("servicePackageDiscountSelected", supportingItems); + this.$emit("quotePageDiscountSelected", supportingItems); }, servicePackage(newValue) { if (newValue !== null) { @@ -118,7 +110,7 @@ export default { return this.availableLineItems ?? []; }, supportingLineItems() { - return this.$store.getters.lineItems?.supportingItems; + return this.$store.getters.lineItems?.supportingItems ?? []; }, servicePackageAnswers() { const cmsWidgetName = this.isInsuranceSelected @@ -149,18 +141,15 @@ export default { ? this.getDiscountedPackagePriceString(answer.Name, false) : this.getDiscountedPackagePriceString( answer.Name, - this.isServicePackageDiscountOnOrder && - this.discountPackageNames == answer.Name + this.hasDiscountForPackage(answer.Name) ), buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName), additionalButtonData: { strikeThroughPrice: this.getPackagePriceString(answer.Name), - servicePackageDiscount: - this.isServicePackageDiscountOnOrder && - this.discountPackageNames == answer.Name, + hasDiscount: this.hasDiscountForPackage(answer.Name), Text: this.isInsuranceSelected ? false - : "Special: Save $" + this.getServicePackageDiscountPrice(), + : "Special: Save $" + this.getDiscountPrice(answer.Name), isInsuranceSelected: this.isInsuranceSelected, }, })); @@ -168,17 +157,8 @@ export default { this.$emit("currentNumberOfPackages", modifiedAnswers.length); return modifiedAnswers; }, - isServicePackageDiscountOnOrder() { - return containsLineItemWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - this.nullSafeAvailableLineItems - ); - }, - discountPackageNames() { - const discountServicePackage = experimentMixin.methods.getSettingValue( - experimentSettings.PROMO_ON_PACKAGE - ); - return getDiscountedPackageName(discountServicePackage); + isDiscountOnOrder() { + return this.availableQuotePageDiscounts?.length > 0; }, frontWipersApplicableForTierTwo() { return shouldFrontWipersBeAvailable( @@ -226,12 +206,6 @@ export default { isRepair() { return this.$store.getters.order.damage.isRepair; }, - servicePackageDiscountParts() { - return findLineItemsWithPartType( - partTypeStrings.SERVICE_PACKAGE_DISCOUNT, - this.nullSafeAvailableLineItems - ); - }, showRecalInServicePackages() { return this.isRecalibrationOnOrder && !this.shouldHideRecalibration; }, @@ -280,16 +254,16 @@ export default { const formattedPriceFloat = parseFloat( this.getPackagePrice(packageName, { discountedPrice: false, - servicePackageDiscount: false, + quotePageDiscount: false, }) ).toFixed(2); return "$" + formattedPriceFloat; }, - getDiscountedPackagePriceString(packageName, servicePackageDiscount) { + getDiscountedPackagePriceString(packageName, quotePageDiscount) { const formattedPriceFloat = parseFloat( this.getPackagePrice(packageName, { discountedPrice: true, - servicePackageDiscount, + quotePageDiscount, }) ).toFixed(2); @@ -298,7 +272,7 @@ export default { } return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat; }, - getPackagePrice(packageName, { discountedPrice = false, servicePackageDiscount = false }) { + getPackagePrice(packageName, { discountedPrice = false, quotePageDiscount = false }) { let lineItemsToPrice = [...this.nullSafeAvailableLineItems]; if (this.isRecalibrationOnOrder && this.shouldHideRecalibration) { @@ -306,17 +280,20 @@ export default { } //remove service package discount part - if (this.isServicePackageDiscountOnOrder) { + if (this.isDiscountOnOrder) { lineItemsToPrice = lineItemsToPrice.filter((item) => { - return item.partType != this.servicePackageDiscountParts[0].partType; + return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; }); } if (discountedPrice) { lineItemsToPrice.push(...removeVapsPromosFromPromoArray(this.activePromos)); } - if (servicePackageDiscount) { - lineItemsToPrice.push(...this.servicePackageDiscountParts); + if (quotePageDiscount) { + const part = this.getDiscountPartForSelectedPackage(packageName); + if (part) { + lineItemsToPrice.push(part); + } } let priceFloat = this.isInsuranceSelected ? 0 @@ -328,14 +305,16 @@ export default { return priceFloat; }, - getServicePackageDiscountPrice() { - if (this.isServicePackageDiscountOnOrder) { - let price = 0; - price += baseMixin.methods.getTotalLineItemPrice( - this.servicePackageDiscountParts[0] - ); + getDiscountPrice(packageName) { + const part = this.getDiscountPartForSelectedPackage(packageName); + + if (part) { + const price = baseMixin.methods.getTotalLineItemPrice(part); + return Math.abs(price); } + + return null; }, getVapsPrice(packageName, applyPromoDiscounts = false) { const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName); @@ -398,13 +377,18 @@ export default { return vapsLineItemsForSelectedPackage; }, - getServicePackageDiscountPartForSelectedPackage(packageName) { - const selectedPackage = this.servicePackageAnswers.filter( - (item) => item.value === packageName - ); - if (selectedPackage?.[0]?.additionalButtonData?.servicePackageDiscount) { - return this.servicePackageDiscountParts; - } else return []; + getDiscountPartForSelectedPackage(packageName) { + if (this.availableQuotePageDiscounts?.length > 0) { + const match = this.availableQuotePageDiscounts.find( + (discountInfo) => discountInfo.packageLevel === packageName + ); + return match?.item; + } + + return null; + }, + hasDiscountForPackage(packageName) { + return !!this.getDiscountPartForSelectedPackage(packageName); }, combineLineItemsWithoutDuplicates(lineItemsOne, lineItemsTwo) { const combinedLineItemArray = [...lineItemsTwo]; diff --git a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue index 441a4f5cb..8bb7e921a 100644 --- a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue +++ b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue @@ -5,7 +5,7 @@ :class="[this.buttonLabelSubCopy ? 'has-subheader' : '']" for="testradio">
-
+

@@ -77,10 +77,7 @@

diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index 5204178de..813a3189a 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -129,9 +129,9 @@ export default { }); return lineItemsArray; }, - filterOutServicePackageDiscountPart(lineItems) { + filterOutQuotePageDiscountPart(lineItems) { const filteredLineItems = lineItems?.filter((item) => { - return !item?.partType?.includes(partTypeStrings.SERVICE_PACKAGE_DISCOUNT); + return !item?.partType?.includes(partTypeStrings.QUOTE_PAGE_DISCOUNT); }); return filteredLineItems; },