From 3969eb4f352123b55c0030f36d13fdd434c68bf7 Mon Sep 17 00:00:00 2001 From: scottkiener-at-safelite Date: Mon, 27 Oct 2025 10:56:26 -0400 Subject: [PATCH 1/2] Revert "Merge pull request #2914 from Safelite/feature/CASH-1529-revert" This reverts commit ea7262594b424d3f0fcbe0740f2a9b05fabe7054, reversing changes made to 71c7625631b187b85cf8b7dc938f4242c91edec1. --- src/fmg-components/cart/cart.vue | 1 + .../promo-modal-question.vue | 35 ++- src/helpers/pricing-helper.js | 20 ++ src/layouts/payment-method/payment-method.vue | 190 ++++++++--------- src/layouts/payment/payment.spec.js | 1 - src/layouts/payment/payment.vue | 114 +--------- src/layouts/quote/quote.vue | 32 +-- src/layouts/schedule/schedule.vue | 199 +++++++----------- src/store/index.js | 37 ++-- 9 files changed, 226 insertions(+), 403 deletions(-) diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index 4da3982cd..e9152dd9d 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -322,6 +322,7 @@ export default { false ); } + this.$emit("itemRemoved"); }, async saveVaps(lineItems) { diff --git a/src/fmg-components/promo-modal-question/promo-modal-question.vue b/src/fmg-components/promo-modal-question/promo-modal-question.vue index 8efad6f3e..1e87d5bb5 100644 --- a/src/fmg-components/promo-modal-question/promo-modal-question.vue +++ b/src/fmg-components/promo-modal-question/promo-modal-question.vue @@ -290,8 +290,18 @@ export default { ); if (promoCodeData.isValid) { if (this.taxPromos) { - const pricedLineItemsToTax = []; - pricedLineItemsToTax.push(...promoCodeData.promoCode); // promoCodeData.promoCode should be an array + const vapsToAdd = getVapsThatNeedToBeAddedToSatisfyPromos( + promoCodeData.promoCode, + this.addableVaps, + this.lineItems + ); + const pricedLineItemsToTax = { + glassParts: this.lineItems.glassParts, + promos: promoCodeData.promoCode, + supportingItems: this.lineItems.supportingItems, + vaps: [...this.lineItems.vaps, ...vapsToAdd], + }; + const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, @@ -314,25 +324,10 @@ export default { // Match all line items to the line items as they are in the store // and rebuild the original structure. - this.lineItems = mapTaxedLineItemsToStoreFormat( - taxedLineItems, - this.lineItems - ); - const taxedVaps = mapTaxedLineItemsToStoreFormat( - taxedLineItems, - this.addableVaps - ); - - const getVaps = getVapsThatNeedToBeAddedToSatisfyPromos( - promoCodeData.promoCode, - taxedVaps, - this.lineItems - ); - - this.lineItems.vaps?.push(...getVaps); + this.lineItems = taxedLineItems; + } else { + this.lineItems?.promos.push(...promoCodeData.promoCode); } - this.lineItems?.promos.push(...promoCodeData.promoCode); - this.$emit("promoAdded", this.lineItems); this.closeModal(); diff --git a/src/helpers/pricing-helper.js b/src/helpers/pricing-helper.js index 9aa317353..0a8b85d7e 100644 --- a/src/helpers/pricing-helper.js +++ b/src/helpers/pricing-helper.js @@ -99,3 +99,23 @@ export async function getPricingByDayPartWithPrice(pageNameToLog) { return pricingResults[0]; } + +export function addPricesToLineItems(lineItems, pricingLineItems) { + lineItems.forEach((lineItem) => { + const lineItemIndex = pricingLineItems.findIndex( + (pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber + ); + + if (lineItem.childParts) { + addPricesToLineItems(lineItem.childParts, pricingLineItems); + } + + const pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0]; + lineItem.laborAmount = pricedLineItem.laborAmount; + lineItem.sellingPrice = pricedLineItem.sellingPrice; + lineItem.kitPrice = pricedLineItem.kitPrice; + lineItem.salesTax = pricedLineItem.salesTax; + }); + + return lineItems; +} diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 2c51f42a1..680d060dc 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -34,7 +34,8 @@ :isItac="isItac" :isNoComp="isNoComp" :isExpandedOnLoad="false" - :isMSRFeeApplicable="isMSRFeeApplicable" /> + :isMSRFeeApplicable="isMSRFeeApplicable" + @itemRemoved="evaluatePromosAndTaxItemsOnOrder" /> { + // this assumes childparts will never be a glass part + lineItem.isChildPart = childPartRecursiveCall; + flattenedArray.push(lineItem); + if (lineItem.childParts) { + flattenedArray = [ + ...flattenedArray, + ...getFlattenedArrayOfLineItemsWithChildParts(lineItem.childParts, true), + ]; + } + }); + + return flattenedArray; +} + export default { name: "paymentMethod", props: { @@ -191,32 +200,14 @@ export default { // Call APIs const cmsContentPromise = fetchCmsContentForPage(to.name); - const lineItemsFromStore = deepClone(store.getters.order.lineItems); - - const frontWipersOnOrder = - lineItemsFromStore.vaps.filter( - (wiper) => wiper.partType == partTypeStrings.FRONT_WIPER - ) ?? []; - - const rearWipersOnOrder = - lineItemsFromStore.vaps.filter( - (wiper) => wiper.partType == partTypeStrings.REAR_WIPER - ) ?? []; - - const orderHasFrontWipers = frontWipersOnOrder.length > 0; - const orderHasRearWipers = rearWipersOnOrder.length > 0; - - const wipersPromise = - !orderHasFrontWipers || !orderHasRearWipers - ? baseMixin.methods.dispatchStoreActionWithLogging( - storeActions.GET_WIPERS, - { - serviceZipCode: store.getters.order.serviceLocation.zipCode, - carId: store.getters.vehicle.carId, - }, - "payment-method" - ) - : Promise.resolve([]); + const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.GET_WIPERS, + { + serviceZipCode: store.getters.order.serviceLocation.zipCode, + carId: store.getters.vehicle.carId, + }, + "payment-method" + ); const rainRepelPromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_RAIN_REPEL, @@ -224,9 +215,6 @@ export default { "payment-method" ); - // const reviewDropdownPromise = reviewDropdown.methods.loadInitialData(); - // (removed temporarily for Heritage parity effort) - const promiseResultMap = [ { resultKey: "cmsContent", @@ -240,57 +228,40 @@ export default { resultKey: "rainRepel", promise: rainRepelPromise, }, - // { - // resultKey: "reviewDropdownData", - // promise: reviewDropdownPromise, - // }, - // (removed temporarily for Heritage parity effort) ]; const resultMap = await settleAllPromises(promiseResultMap); + let lineItemsFromStore = deepClone(store.getters.order.lineItems); const glassParts = lineItemsFromStore.glassParts ?? []; const supportingItems = lineItemsFromStore.supportingItems ?? []; const vaps = lineItemsFromStore.vaps ?? []; - // if the order already has wipers on it from the quote page, use those as the available wipers - // instead of what comes from the backend. This is to prevent issues with part interchange. - const availableFrontWipers = orderHasFrontWipers - ? frontWipersOnOrder - : (resultMap.wipers.filter((wiper) => wiper.partType == partTypeStrings.FRONT_WIPER) ?? - []); - const availableRearWipers = orderHasRearWipers - ? rearWipersOnOrder - : (resultMap.wipers.filter((wiper) => wiper.partType == partTypeStrings.REAR_WIPER) ?? - []); + const availableVaps = [resultMap.rainRepel, ...resultMap.wipers]; - const allLineItems = [ - resultMap.rainRepel, - ...supportingItems, - ...availableFrontWipers, - ...availableRearWipers, + const lineItemsOnOrderAndAvailableVaps = [ + ...availableVaps, ...glassParts, + ...supportingItems, ...vaps, ]; - const lineItemsToTax = Array.from( - new Map(allLineItems.map((item) => [item.partNumber, item])).values() - ); - - const availableVaps = [ - resultMap.rainRepel, - ...availableFrontWipers, - ...availableRearWipers, - ]; - - const pricedLineItemsToTax = await baseMixin.methods.dispatchStoreActionWithLogging( + // All line items are already priced except availableVaps + // Price everything again to ensure that serverData has all values + // Specifically this addresses an error where insurance client glass parts are not in serverData + // See CASH-1713 for details + let pricedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - availableLineItems: lineItemsToTax, + availableLineItems: lineItemsOnOrderAndAvailableVaps, }, "payment-method", false ); + pricedLineItems = getFlattenedArrayOfLineItemsWithChildParts(pricedLineItems); + + // Add prices to the availableVaps + const pricedAvailableVaps = addPricesToLineItems(availableVaps, pricedLineItems); // Promo logic // Populate the previous state of promos for toast message usage in "next()" @@ -298,22 +269,38 @@ export default { const oldInactivePromos = store.getters.order.payment.inactivePromos?.slice(0); const promoCodeFromQueryString = consumeQueryFromStash(queryStrings.PROMO); + // New promos are saved to store with this const { validatePromoResponse, revalidatePromoResponse } = await revalidatePromosAndValidateQueryStringPromo( promoCodeFromQueryString, - pricedLineItemsToTax, + lineItemsOnOrderAndAvailableVaps, "payment-method" ); + // update lineItemsFromStore with newly added promos + let lineItemsForCart = deepClone(store.getters.order.lineItems); + delete lineItemsForCart.serverData; - // Add newly validated promos to the array to get taxed - const newValidatedPromos = validatePromoResponse?.orderPromos ?? []; - newValidatedPromos.push( - ...(revalidatePromoResponse ? revalidatePromoResponse.promoLineItems : []) - ); - pricedLineItemsToTax.push(...newValidatedPromos); // End of promo logic - const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( + const vapsToAddToCart = getVapsThatNeedToBeAddedToSatisfyPromos( + lineItemsForCart.promos ?? [], + availableVaps, + lineItemsForCart + ); + // Add prices to all line items, sometimes they are not there when they come back from heritage + // See CASH-1713 for details + lineItemsForCart.glassParts = addPricesToLineItems( + lineItemsForCart.glassParts ?? [], + pricedLineItems + ); + lineItemsForCart.supportingItems = addPricesToLineItems( + lineItemsForCart.supportingItems ?? [], + pricedLineItems + ); + lineItemsForCart.vaps = addPricesToLineItems(lineItemsForCart.vaps ?? [], pricedLineItems); + lineItemsForCart.vaps.push(...vapsToAddToCart); + // Tax items on order + lineItemsForCart = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { billToAccountNumber: store.getters.payment.billToAccountNumber, @@ -322,31 +309,17 @@ export default { serviceLocationCity: store.getters.order.serviceLocation.city, serviceLocationState: store.getters.order.serviceLocation.state, serviceLocationZipCode: store.getters.order.serviceLocation.zipCode, - pricedLineItems: pricedLineItemsToTax, + pricedLineItems: lineItemsForCart, }, "payment-method", false ); - // Match all line items to the line items as they are in the store - // and rebuild the original structure. - const lineItems = mapTaxedLineItemsToStoreFormat(taxedLineItems, lineItemsFromStore); - const taxedVaps = mapTaxedLineItemsToStoreFormat(taxedLineItems, availableVaps); - - lineItems.promos = newValidatedPromos ?? []; - const vapsToAddToCart = getVapsThatNeedToBeAddedToSatisfyPromos( - newValidatedPromos, - taxedVaps, - lineItems - ); - lineItems.vaps = lineItems.vaps ?? []; - lineItems.vaps.push(...vapsToAddToCart); - // Call the "next" function to complete the transition to this page. next((vm) => { vm.setCmsContent(resultMap.cmsContent); - vm.availableVaps = taxedVaps; - vm.lineItems = lineItems; + vm.availableVaps = pricedAvailableVaps; + vm.lineItems = lineItemsForCart; vm.inactivePromos = removeCurrentlyActivePromoCodesFromInactivePromos( vm.lineItems.promos, vm.inactivePromos @@ -641,6 +614,28 @@ export default { this.pageName ); }, + async evaluatePromosAndTaxItemsOnOrder() { + //Revalidate promos if there are any inactive, or active promos + const hasInactivePromos = this.inactivePromos.length > 0; + const hasActivePromos = this.lineItems.promos.length > 0; + if (hasInactivePromos || hasActivePromos) { + await this.revalidatePromos(); + } + this.lineItems = await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, + { + billToAccountNumber: store.getters.payment.billToAccountNumber, + providerNumber: store.getters.order.serviceLocation.provider.providerNumber, + appointmentType: store.getters.order.serviceLocation.appointmentType, + serviceLocationCity: store.getters.order.serviceLocation.city, + serviceLocationState: store.getters.order.serviceLocation.state, + serviceLocationZipCode: store.getters.order.serviceLocation.zipCode, + pricedLineItems: this.lineItems, + }, + "payment-method", + false + ); + }, hasSubmittedOrder() { return baseMixin.methods.hasSubmittedOrder(); }, @@ -861,7 +856,6 @@ export default { ) { return; } - if (oldValue.promos.length < newValue.promos.length) { const oldPromoCodes = oldValue.promos.map( (promoObject) => promoObject.promoCode diff --git a/src/layouts/payment/payment.spec.js b/src/layouts/payment/payment.spec.js index ad98814d2..1b36d0644 100644 --- a/src/layouts/payment/payment.spec.js +++ b/src/layouts/payment/payment.spec.js @@ -319,7 +319,6 @@ describe("payment.vue", () => { ); // Assert - expect(vmMock.availableVaps).not.toBeUndefined(); expect(vmMock.lineItems).not.toBeUndefined(); expect(vmMock.setCmsContent).toBeCalled(); diff --git a/src/layouts/payment/payment.vue b/src/layouts/payment/payment.vue index 992795321..b8e481174 100644 --- a/src/layouts/payment/payment.vue +++ b/src/layouts/payment/payment.vue @@ -42,7 +42,7 @@ { vm.setCmsContent(resultMap.cmsContent); - vm.availableVaps = taxedVaps; - vm.lineItems = lineItems; + vm.lineItems = deepClone(store.getters.order.lineItems); vm.$nextTick(() => { if (vm.$refs.cart) { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index c76222cac..8bab96d5f 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -65,6 +65,7 @@ pageName="quote" :taxPromos="false" :useDefaultCashParentAccount="true" + @promoAdded="promoAdded" modalWidgetName="PromoModalWidget" /> @@ -576,9 +577,6 @@ export default { isInsuranceContinueButtonText() { return this.getCmsContent("isInsuranceContinueButtonText", "Text"); }, - lineItemsCloneForWatcher() { - return Object.assign({}, this.lineItems); - }, isRecalibrationOnOrder() { return store.getters.isRecalibrationOnOrder; }, @@ -854,31 +852,9 @@ export default { await this.forwardButtonAction(); } }, - }, - watch: { - lineItemsCloneForWatcher: { - handler(newValue, oldValue) { - if ( - !oldValue || - oldValue.length == 0 || - !oldValue.vaps || - !newValue || - newValue.length == 0 - ) { - return; - } - if (oldValue.promos.length < newValue.promos.length) { - const oldPromoCodes = oldValue.promos.map( - (promoObject) => promoObject.promoCode - ); - const newlyActivatedPromoCodes = newValue.promos.filter( - (newPromo) => !oldPromoCodes.includes(newPromo.promoCode) - ); - const alert = createPromoSuccessAlert(newlyActivatedPromoCodes[0].promoCode); - this.$refs.funnelHeader.pushGlobalAlert(alert, alert.shouldAutoFade); - } - }, - deep: true, + promoAdded(lineItems) { + const alert = createPromoSuccessAlert(lineItems.promos[0].promoCode); + this.$refs.funnelHeader.pushGlobalAlert(alert, alert.shouldAutoFade); }, }, components: { diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 716c819e2..7c9d9f444 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -460,111 +460,47 @@ export default { }; }, async beforeRouteEnter(to, from, next) { - const isPricingByDayExperiment = experimentMixin.methods.hasSettingEqualTo( - experimentSettings.PRICING_BY_DAY, - "true" - ); - const showPricingByDay = !store.getters.payment.isInsurance && isPricingByDayExperiment; + const serviceZipCode = store.getters.order.serviceLocation.zipCode; - // Get pricingByDayBasePrice needed for Pricing By Day - const lineItems = deepClone(store.getters.order.lineItems); - const isRecalibrationOnOrder = store.getters.isRecalibrationOnOrder; - const shouldHideRecalibration = - experimentMixin.methods.hasSettingEqualTo( - experimentSettings.RECAL_PRICE_REMOVE, - "true" - ) && isRecalibrationOnOrder; - const glassParts = - isRecalibrationOnOrder && shouldHideRecalibration - ? getItemsWithoutRecalParts(lineItems.glassParts) - : (lineItems.glassParts ?? []); - const supportingItemsWithoutFees = baseMixin.methods.filterOutCertainPartTypesOrNumbers( - lineItems.supportingItems, - { - partNumbersToRemove: [ - partNumberStrings.RECYCLE_FEE, - partNumberStrings.PRICING_BY_DAY_UPCHARGE, - ], - } - ); - const lineItemsToBePriced = { - glassParts: glassParts, - supportingItems: supportingItemsWithoutFees, - vaps: lineItems.vaps ?? [], - promos: lineItems.promos ?? [], - }; - const priceString = getAmountDue(lineItemsToBePriced, false); // pass the IncludeTax param as false - const priceStringIntegerRoundedDown = priceString?.split(".")[0]; // same method used as getDisplayPrice() in service-package-radio used on /quote - const pricingByDayBasePrice = parseInt(priceStringIntegerRoundedDown); - let includePricingByDayUpcharge = false; - let appointmentType = store.getters.order.serviceLocation.appointmentType; - - // Check to see if date should be pre-selected - let scheduleFromStore = await store.getters.order.schedule; - let preSelectedDate; - - if (scheduleFromStore.date && scheduleFromStore.date.length > 0) { - preSelectedDate = scheduleFromStore.date; - - if (appointmentType === AppointmentTypeStrings.MOBILE) { - preSelectedDate += "-mobile"; - } - - // Check to see if pre-selected date should have pricing by day upcharge - if (showPricingByDay) { - // is this preSelectedDate a higher priced pricingByDay day? - const dayIndex = convertDateStringToDate(scheduleFromStore?.date).getDay(); - const dayObject = DAYS_OF_WEEK[dayIndex]; - if (dayObject.isPricingByDayUpchargeDay) { - includePricingByDayUpcharge = true; - } - } - } - - // Set up promises const cmsContentPromise = fetchCmsContentForPage(to.name); - const alertReasonsPromise = locationAlerts.methods.loadInitialData( store.getters.order.serviceLocation.zipCodeCtu, store.getters.order.serviceLocation.provider?.address?.zipCodeCtu ); - - const serviceZipCode = store.getters.order.serviceLocation.zipCode; - const zipCodeDataPromise = getZipCodeData(serviceZipCode, to.name); const serviceabilityDetailsPromise = getServiceabilityDetails( serviceZipCode, null, - to.name + "schedule" + ); + let zipCodeData; + const zipCodeDataPromise = getZipCodeData(serviceZipCode, to.name); + let shopProviderData; + const shopProviderDataPromise = getShopProviderData(serviceZipCode, to.name); + const zipCodeDataAndShopProviderDataPromise = Promise.all([ + zipCodeDataPromise, + shopProviderDataPromise, + ]); + const mobileFeePartPromise = zipCodeDataAndShopProviderDataPromise.then( + ([zipCodeDataResult, shopProviderDataResult]) => { + zipCodeData = zipCodeDataResult; + shopProviderData = shopProviderDataResult; + return baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.GET_MOBILE_FEE_PART, + { + serviceZipCode: serviceZipCode, + serviceZipCodeCtu: zipCodeData.zipCodeCtu, + mobileProviderNumber: shopProviderData.data.mobileProviderNumber, + }, + to.name, + false + ); + } ); - const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode, to.name); - const shopProviderData = await getShopProviderData(serviceZipCode, to.name); - const providerNumber = shopProviderData?.data?.shopProviders[0]?.providerNumber; - - // Get pricingByDayUpcharge needed for Pricing By Day - const pricingByDayUpchargePartPromise = showPricingByDay - ? getPricingByDayPartWithPrice() - : null; - const premiumFeePromise = baseMixin.methods.dispatchStoreActionWithLogging( storeActions.GET_MOBILE_PREMIUM_FEE, null, to.name ); - const premiumFeeWithPricePromise = premiumFeePromise.then((result) => { - if (result.data) { - return baseMixin.methods.dispatchStoreActionWithLogging( - storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, - { - availableLineItems: [result.data], - }, - to.name, - false - ); - } else { - return result.data; - } - }); - // Settle promises and get results const promiseResultMap = [ { @@ -575,18 +511,6 @@ export default { resultKey: "alertReasons", promise: alertReasonsPromise, }, - { - resultKey: "pricingByDayUpchargePart", - promise: pricingByDayUpchargePartPromise, - }, - { - resultKey: "premiumFeeWithPrice", - promise: premiumFeeWithPricePromise, - }, - { - resultKey: "zipCodeData", - promise: zipCodeDataPromise, - }, { resultKey: "mobileFeePart", promise: mobileFeePartPromise, @@ -595,39 +519,70 @@ export default { resultKey: "serviceabilityDetails", promise: serviceabilityDetailsPromise, }, + { + resultKey: "premiumFee", + promise: premiumFeePromise, + }, ]; - const resultMap = await settleAllPromises(promiseResultMap); + const itemsToPrice = []; + if (resultMap.mobileFeePart) { + itemsToPrice.push(resultMap.mobileFeePart); + } + if (resultMap.premiumFee) { + itemsToPrice.push(resultMap.premiumFee); + } - // add pricing by day data - const pricingByDayUpcharge = - showPricingByDay && resultMap.pricingByDayUpchargePart - ? await baseMixin.methods.getTotalLineItemPrice( - resultMap.pricingByDayUpchargePart, - false - ) - : null; + let pricedMobileFeePart = null; + let pricedPremiumFee = null; + + if (itemsToPrice.length) { + const pricedItems = await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, + { + availableLineItems: itemsToPrice, + }, + to.name, + false + ); + pricedMobileFeePart = pricedItems.find( + (item) => item.partNumber === resultMap.mobileFeePart.partNumber + ); + pricedPremiumFee = pricedItems.find( + (item) => item.partNumber === resultMap.premiumFee.partNumber + ); + } + + let appointmentType = store.getters.order.serviceLocation.appointmentType; + // Check to see if date should be pre-selected + let scheduleFromStore = await store.getters.order.schedule; + let preSelectedDate; + if (scheduleFromStore.date && scheduleFromStore.date.length > 0) { + preSelectedDate = scheduleFromStore.date; + + if (appointmentType === AppointmentTypeStrings.MOBILE) { + preSelectedDate += "-mobile"; + } + } // Call the "next" function to complete the transition to this page. next((vm) => { vm.setCmsContent(resultMap.cmsContent); vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons); - vm.mobilePremiumAppointmentFee = resultMap.premiumFeeWithPrice - ? resultMap.premiumFeeWithPrice[0] - : null; + vm.mobilePremiumAppointmentFee = pricedPremiumFee; vm.updateFooterButtonText(vm.selectedTimeSlotInfo); - vm.pricingByDayUpchargeLineItem = resultMap.pricingByDayUpchargePart; - vm.includePricingByDayUpcharge = includePricingByDayUpcharge; - vm.isPricingByDayExperiment = isPricingByDayExperiment; - vm.pricingByDayBasePrice = pricingByDayBasePrice; - vm.pricingByDayUpcharge = pricingByDayUpcharge; - vm.showPricingByDay = showPricingByDay; + vm.pricingByDayUpchargeLineItem = null; // Pricing By Day Upcharge Line Item is not used in this version + vm.includePricingByDayUpcharge = false; // Pricing By Day Upcharge is not used in this version + vm.isPricingByDayExperiment = false; // Pricing By Day Experiment is not used in this version + vm.pricingByDayBasePrice = null; // Pricing By Day Base Price is not used in this version + vm.pricingByDayUpcharge = null; // Pricing By Day Upcharge is not used in this version + vm.showPricingByDay = false; // Pricing By Day is not used in this version vm.preSelectedDate = preSelectedDate; vm.appointmentType = appointmentType; vm.setData( - resultMap.zipCodeData, + zipCodeData, resultMap.serviceabilityDetails, - resultMap.mobileFeePart, + pricedMobileFeePart, shopProviderData.data ); vm.initializeDatePicker(); diff --git a/src/store/index.js b/src/store/index.js index 475076c86..dbee4f357 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -59,6 +59,7 @@ import { } from "@/helpers/recal-helper"; import { externalParameterStatus } from "@/constants/external-parameters"; import { experimentSettings } from "@/constants/experiments"; +import { addPricesToLineItems } from "@/helpers/pricing-helper"; // Export State const getDefaultState = () => { @@ -3063,8 +3064,14 @@ export const actions = { pageNameToLog, } ) { + const arrayOfLineItems = [ + ...(pricedLineItems.glassParts ?? []), + ...(pricedLineItems.promos ?? []), + ...(pricedLineItems.supportingItems ?? []), + ...(pricedLineItems.vaps ?? []), + ]; const flattenedLineItemsWithChildParts = - getFlattenedArrayOfLineItemsWithChildParts(pricedLineItems); + getFlattenedArrayOfLineItemsWithChildParts(arrayOfLineItems); const lineItemsWithOnlyPriceInfo = flattenedLineItemsWithChildParts.map((lineItem) => ({ partNumber: lineItem.partNumber, @@ -3113,8 +3120,12 @@ export const actions = { }); context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData); - - pricedLineItems = addTaxesToPricedLineItems(pricedLineItems, response.data.taxedLineItems); + Object.keys(pricedLineItems).forEach((key) => { + pricedLineItems[key] = addTaxesToPricedLineItems( + pricedLineItems[key] ?? [], + response.data.taxedLineItems + ); + }); return pricedLineItems; }, @@ -3796,26 +3807,6 @@ function convertGlassPieceNamingFromApi(glassArray) { return glassArray; } -function addPricesToLineItems(lineItems, pricingLineItems) { - lineItems.forEach((lineItem) => { - const lineItemIndex = pricingLineItems.findIndex( - (pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber - ); - - if (lineItem.childParts) { - addPricesToLineItems(lineItem.childParts, pricingLineItems); - } - - const pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0]; - lineItem.laborAmount = pricedLineItem.laborAmount; - lineItem.sellingPrice = pricedLineItem.sellingPrice; - lineItem.kitPrice = pricedLineItem.kitPrice; - lineItem.salesTax = pricedLineItem.salesTax; - }); - - return lineItems; -} - function addTaxesToPricedLineItems(pricedLineItems, taxingLineItems = []) { pricedLineItems.forEach((pricedLineItem) => { const lineItemIndex = taxingLineItems.findIndex( From 87d83ee21b4bb1a6f17c9f8753b4ac48f2887a11 Mon Sep 17 00:00:00 2001 From: scottkiener-at-safelite Date: Mon, 27 Oct 2025 11:37:43 -0400 Subject: [PATCH 2/2] Make lineItems pricing lineup safer --- src/helpers/pricing-helper.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/helpers/pricing-helper.js b/src/helpers/pricing-helper.js index 0a8b85d7e..68de04515 100644 --- a/src/helpers/pricing-helper.js +++ b/src/helpers/pricing-helper.js @@ -110,11 +110,13 @@ export function addPricesToLineItems(lineItems, pricingLineItems) { addPricesToLineItems(lineItem.childParts, pricingLineItems); } - const pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0]; - lineItem.laborAmount = pricedLineItem.laborAmount; - lineItem.sellingPrice = pricedLineItem.sellingPrice; - lineItem.kitPrice = pricedLineItem.kitPrice; - lineItem.salesTax = pricedLineItem.salesTax; + if (lineItemIndex !== -1) { + const pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0]; + lineItem.laborAmount = pricedLineItem.laborAmount; + lineItem.sellingPrice = pricedLineItem.sellingPrice; + lineItem.kitPrice = pricedLineItem.kitPrice; + lineItem.salesTax = pricedLineItem.salesTax; + } }); return lineItems;