From 9dc65e8df5175567aa2f09ebb5e73bff39c848b7 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 10:28:08 -0400 Subject: [PATCH 01/12] CASH-1713 | Add prices to wipers again --- src/layouts/payment-method/payment-method.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index abee992bf..502321d2e 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -269,7 +269,7 @@ export default { availableVaps, lineItemsForCart ); - lineItemsForCart.vaps = lineItemsForCart.vaps ?? []; + lineItemsForCart.vaps = addPricesToLineItems(lineItemsForCart.vaps, pricedLineItems) ?? []; lineItemsForCart.vaps.push(...vapsToAddToCart); // Tax items on order lineItemsForCart = await baseMixin.methods.dispatchStoreActionWithLogging( From 60163cef33d5d8424825ffd2436caf803afbcfd5 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 10:35:14 -0400 Subject: [PATCH 02/12] Null check --- src/layouts/payment-method/payment-method.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 502321d2e..f903d0c16 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -269,7 +269,7 @@ export default { availableVaps, lineItemsForCart ); - lineItemsForCart.vaps = addPricesToLineItems(lineItemsForCart.vaps, pricedLineItems) ?? []; + lineItemsForCart.vaps = addPricesToLineItems(lineItemsForCart.vaps ?? [], pricedLineItems); lineItemsForCart.vaps.push(...vapsToAddToCart); // Tax items on order lineItemsForCart = await baseMixin.methods.dispatchStoreActionWithLogging( From 15321506ea34c0620a184aa6b50ca01ea6ad4a86 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 12:02:21 -0400 Subject: [PATCH 03/12] CASH-1713 | Add prices to all items from store --- src/layouts/payment-method/payment-method.vue | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index f903d0c16..d22ea1534 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -269,6 +269,16 @@ export default { 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 From 7c59a8d0e5a326ac8a4c39c3bdcf95fb09d9dc26 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 13:47:51 -0400 Subject: [PATCH 04/12] CASH-1713 | Send in flattened priced items --- src/layouts/payment-method/payment-method.vue | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index d22ea1534..680d060dc 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -174,6 +174,23 @@ import { Field } from "vee-validate"; defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED)); defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED)); +function getFlattenedArrayOfLineItemsWithChildParts(lineItems, childPartRecursiveCall = false) { + let flattenedArray = []; + lineItems?.forEach((lineItem) => { + // this assumes childparts will never be a glass part + lineItem.isChildPart = childPartRecursiveCall; + flattenedArray.push(lineItem); + if (lineItem.childParts) { + flattenedArray = [ + ...flattenedArray, + ...getFlattenedArrayOfLineItemsWithChildParts(lineItem.childParts, true), + ]; + } + }); + + return flattenedArray; +} + export default { name: "paymentMethod", props: { @@ -233,7 +250,7 @@ export default { // 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 - const pricedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( + let pricedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { availableLineItems: lineItemsOnOrderAndAvailableVaps, @@ -241,6 +258,7 @@ export default { "payment-method", false ); + pricedLineItems = getFlattenedArrayOfLineItemsWithChildParts(pricedLineItems); // Add prices to the availableVaps const pricedAvailableVaps = addPricesToLineItems(availableVaps, pricedLineItems); From b5933955d94fe11d041b9f4eedcbc1106c3845d9 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 14:50:38 -0400 Subject: [PATCH 05/12] Revert "Merge pull request #2911 from Safelite/feature/CASH-1713" This reverts commit 71c7625631b187b85cf8b7dc938f4242c91edec1, reversing changes made to 9ffd1ec2be56b070057757b505d14ec41da7234c. --- src/layouts/payment-method/payment-method.vue | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 680d060dc..d22ea1534 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -174,23 +174,6 @@ import { Field } from "vee-validate"; defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED)); defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED)); -function getFlattenedArrayOfLineItemsWithChildParts(lineItems, childPartRecursiveCall = false) { - let flattenedArray = []; - lineItems?.forEach((lineItem) => { - // this assumes childparts will never be a glass part - lineItem.isChildPart = childPartRecursiveCall; - flattenedArray.push(lineItem); - if (lineItem.childParts) { - flattenedArray = [ - ...flattenedArray, - ...getFlattenedArrayOfLineItemsWithChildParts(lineItem.childParts, true), - ]; - } - }); - - return flattenedArray; -} - export default { name: "paymentMethod", props: { @@ -250,7 +233,7 @@ export default { // 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( + const pricedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { availableLineItems: lineItemsOnOrderAndAvailableVaps, @@ -258,7 +241,6 @@ export default { "payment-method", false ); - pricedLineItems = getFlattenedArrayOfLineItemsWithChildParts(pricedLineItems); // Add prices to the availableVaps const pricedAvailableVaps = addPricesToLineItems(availableVaps, pricedLineItems); From 33906bd83a7916e3cd27b5480d3f2f5cad7ae7e1 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 14:51:13 -0400 Subject: [PATCH 06/12] Revert "Merge pull request #2909 from Safelite/feature/CASH-1713" This reverts commit 9ffd1ec2be56b070057757b505d14ec41da7234c, reversing changes made to e798eef8c5007f2985e5143946851299068e8424. --- src/layouts/payment-method/payment-method.vue | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index d22ea1534..f903d0c16 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -269,16 +269,6 @@ export default { 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 From 75a806d124509c83b9d66a3c2793eadf94f7dd99 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 14:51:35 -0400 Subject: [PATCH 07/12] Revert "Merge pull request #2906 from Safelite/feature/CASH-1713" This reverts commit e798eef8c5007f2985e5143946851299068e8424, reversing changes made to 7b33d8eeb22df1831b4f4e8d15d3c651d9b3feeb. --- src/layouts/payment-method/payment-method.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index f903d0c16..502321d2e 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -269,7 +269,7 @@ export default { availableVaps, lineItemsForCart ); - lineItemsForCart.vaps = addPricesToLineItems(lineItemsForCart.vaps ?? [], pricedLineItems); + lineItemsForCart.vaps = addPricesToLineItems(lineItemsForCart.vaps, pricedLineItems) ?? []; lineItemsForCart.vaps.push(...vapsToAddToCart); // Tax items on order lineItemsForCart = await baseMixin.methods.dispatchStoreActionWithLogging( From 7e4e1ba1a746400f214a3814d63f585359a987fe Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 14:51:57 -0400 Subject: [PATCH 08/12] Revert "Merge pull request #2905 from Safelite/feature/CASH-1713" This reverts commit 7b33d8eeb22df1831b4f4e8d15d3c651d9b3feeb, reversing changes made to 2a2e3383d265e4ce9d61381207f257b8441b2864. --- src/layouts/payment-method/payment-method.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 502321d2e..abee992bf 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -269,7 +269,7 @@ export default { availableVaps, lineItemsForCart ); - lineItemsForCart.vaps = addPricesToLineItems(lineItemsForCart.vaps, pricedLineItems) ?? []; + lineItemsForCart.vaps = lineItemsForCart.vaps ?? []; lineItemsForCart.vaps.push(...vapsToAddToCart); // Tax items on order lineItemsForCart = await baseMixin.methods.dispatchStoreActionWithLogging( From 44939c508e435ff4f090886b334c1d48c0073f56 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 14:52:19 -0400 Subject: [PATCH 09/12] Revert "Merge pull request #2903 from Safelite/feature/CASH-1713" This reverts commit 2a2e3383d265e4ce9d61381207f257b8441b2864, reversing changes made to dbcf5351aefced01a4535eef1df999a364cf4193. --- src/helpers/pricing-helper.js | 20 ----------- src/layouts/payment-method/payment-method.vue | 35 ++++++++++--------- src/store/index.js | 21 ++++++++++- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/helpers/pricing-helper.js b/src/helpers/pricing-helper.js index 0a8b85d7e..9aa317353 100644 --- a/src/helpers/pricing-helper.js +++ b/src/helpers/pricing-helper.js @@ -99,23 +99,3 @@ 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 abee992bf..ffb3d2353 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -155,6 +155,7 @@ import { getNewlyInactivatedPromos, } from "@/helpers/promotions-helper"; import { queryStrings } from "@/constants/query-strings"; +import { getQuerystringParameter } from "@/helpers/querystring-helper"; import { deepClone } from "@/helpers/object-helper"; import { Form } from "vee-validate"; @@ -162,10 +163,18 @@ import { defineRule } from "vee-validate"; import { required } from "@/helpers/validation-rules"; import { errorMessages } from "@/constants/error-messages"; import { AppointmentTypeStrings } from "@/constants/schedule-constants"; +import { partTypeStrings } from "@/constants/part-type-strings"; +import { mapTaxedLineItemsToStoreFormat } from "../../store"; import { coverageStatus } from "@/constants/insurance"; +import { containsLineItemWithPartType } from "@/helpers/service-package-helper"; import { containsRecalParts } from "@/helpers/recal-helper"; import { getBoolFromString } from "@/helpers/boolean-helper"; -import { getAmountDue, addPricesToLineItems } from "@/helpers/pricing-helper.js"; +import { + getDisplayAmountDue, + getAmountDue, + getSubTotal, + getSalesTax, +} from "@/helpers/pricing-helper.js"; import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stash"; import { debugLog } from "@/helpers/debug-log-helper"; import { ErrorMessage } from "vee-validate"; @@ -222,28 +231,21 @@ export default { const availableVaps = [resultMap.rainRepel, ...resultMap.wipers]; - const lineItemsOnOrderAndAvailableVaps = [ - ...availableVaps, - ...glassParts, - ...supportingItems, - ...vaps, - ]; - - // 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 - const pricedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( + const pricedAvailableVaps = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - availableLineItems: lineItemsOnOrderAndAvailableVaps, + availableLineItems: availableVaps, }, "payment-method", false ); - // Add prices to the availableVaps - const pricedAvailableVaps = addPricesToLineItems(availableVaps, pricedLineItems); + const lineItemsOnOrderAndAvailableVaps = [ + ...pricedAvailableVaps, + ...glassParts, + ...supportingItems, + ...vaps, + ]; // Promo logic // Populate the previous state of promos for toast message usage in "next()" @@ -263,6 +265,7 @@ export default { delete lineItemsForCart.serverData; // End of promo logic + // const vapsToAddToCart = getVapsThatNeedToBeAddedToSatisfyPromos( lineItemsForCart.promos ?? [], diff --git a/src/store/index.js b/src/store/index.js index ef67b84a0..1fa9b4f14 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -59,7 +59,6 @@ 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 = () => { @@ -3702,6 +3701,26 @@ 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 8909bbe49c60869d658bd42f7cb584fa789a7737 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 14:52:42 -0400 Subject: [PATCH 10/12] Revert "Merge pull request #2888 from Safelite/feature/CASH-1640" This reverts commit 396e15451f665ccb8dc65a541f604bb857599810, reversing changes made to a73410fc276a6053d32017c135177c4417cdf60e. --- src/layouts/payment-method/payment-method.vue | 10 +- src/layouts/payment/payment.spec.js | 1 + src/layouts/payment/payment.vue | 114 +++++++++++++++++- 3 files changed, 114 insertions(+), 11 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index ffb3d2353..214b6111e 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -35,7 +35,7 @@ :isNoComp="isNoComp" :isExpandedOnLoad="false" :isMSRFeeApplicable="isMSRFeeApplicable" - @itemRemoved="evaluatePromosAndTaxItemsOnOrder" /> + @itemRemoved="reTaxItemsOnOrder" /> 0; - const hasActivePromos = this.lineItems.promos.length > 0; - if (hasInactivePromos || hasActivePromos) { - await this.revalidatePromos(); - } + async reTaxItemsOnOrder() { this.lineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { diff --git a/src/layouts/payment/payment.spec.js b/src/layouts/payment/payment.spec.js index 1b36d0644..ad98814d2 100644 --- a/src/layouts/payment/payment.spec.js +++ b/src/layouts/payment/payment.spec.js @@ -319,6 +319,7 @@ 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 b8e481174..992795321 100644 --- a/src/layouts/payment/payment.vue +++ b/src/layouts/payment/payment.vue @@ -42,7 +42,7 @@ { vm.setCmsContent(resultMap.cmsContent); - vm.lineItems = deepClone(store.getters.order.lineItems); + vm.availableVaps = taxedVaps; + vm.lineItems = lineItems; vm.$nextTick(() => { if (vm.$refs.cart) { From a7b46c3e17547108ad6f40e681016a76893cc0b9 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 14:56:47 -0400 Subject: [PATCH 11/12] Revert "Merge pull request #2874 from Safelite/feature/CASH-1529" This reverts commit 49726644053e027f2bc2bb792118bb8e13ccd150, reversing changes made to 9eacf1d04d392b497d6405cf969f4a0e5ba2f0e3. --- src/fmg-components/cart/cart.vue | 1 - .../promo-modal-question.vue | 35 +-- src/layouts/payment-method/payment-method.vue | 153 +++++++++----- src/layouts/quote/quote.vue | 32 ++- src/layouts/schedule/schedule.vue | 199 +++++++++++------- src/store/index.js | 16 +- 6 files changed, 268 insertions(+), 168 deletions(-) diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue index e9152dd9d..4da3982cd 100644 --- a/src/fmg-components/cart/cart.vue +++ b/src/fmg-components/cart/cart.vue @@ -322,7 +322,6 @@ 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 1e87d5bb5..8efad6f3e 100644 --- a/src/fmg-components/promo-modal-question/promo-modal-question.vue +++ b/src/fmg-components/promo-modal-question/promo-modal-question.vue @@ -290,18 +290,8 @@ export default { ); if (promoCodeData.isValid) { if (this.taxPromos) { - 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 pricedLineItemsToTax = []; + pricedLineItemsToTax.push(...promoCodeData.promoCode); // promoCodeData.promoCode should be an array const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, @@ -324,10 +314,25 @@ export default { // Match all line items to the line items as they are in the store // and rebuild the original structure. - this.lineItems = taxedLineItems; - } else { - this.lineItems?.promos.push(...promoCodeData.promoCode); + 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?.promos.push(...promoCodeData.promoCode); + this.$emit("promoAdded", this.lineItems); this.closeModal(); diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 214b6111e..3f7124f84 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -34,8 +34,7 @@ :isItac="isItac" :isNoComp="isNoComp" :isExpandedOnLoad="false" - :isMSRFeeApplicable="isMSRFeeApplicable" - @itemRemoved="reTaxItemsOnOrder" /> + :isMSRFeeApplicable="isMSRFeeApplicable" /> 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 rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.GET_RAIN_DEFENSE, null, "payment-method" ); + // const reviewDropdownPromise = reviewDropdown.methods.loadInitialData(); + // (removed temporarily for Heritage parity effort) + const promiseResultMap = [ { resultKey: "cmsContent", @@ -220,62 +240,80 @@ 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 ?? []; - const availableVaps = [resultMap.rainRepel, ...resultMap.wipers]; + // 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 pricedAvailableVaps = await baseMixin.methods.dispatchStoreActionWithLogging( + const allLineItems = [ + resultMap.rainDefense, + ...supportingItems, + ...availableFrontWipers, + ...availableRearWipers, + ...glassParts, + ...vaps, + ]; + + const lineItemsToTax = Array.from( + new Map(allLineItems.map((item) => [item.partNumber, item])).values() + ); + + const availableVaps = [ + resultMap.rainDefense, + ...availableFrontWipers, + ...availableRearWipers, + ]; + + const pricedLineItemsToTax = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { - availableLineItems: availableVaps, + availableLineItems: lineItemsToTax, }, "payment-method", false ); - const lineItemsOnOrderAndAvailableVaps = [ - ...pricedAvailableVaps, - ...glassParts, - ...supportingItems, - ...vaps, - ]; - // Promo logic // Populate the previous state of promos for toast message usage in "next()" const oldActivePromos = store.getters.lineItems.promos?.slice(0); 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, - lineItemsOnOrderAndAvailableVaps, + pricedLineItemsToTax, "payment-method" ); - // update lineItemsFromStore with newly added promos - let lineItemsForCart = deepClone(store.getters.order.lineItems); - delete lineItemsForCart.serverData; - // End of promo logic - // - - const vapsToAddToCart = getVapsThatNeedToBeAddedToSatisfyPromos( - lineItemsForCart.promos ?? [], - availableVaps, - lineItemsForCart + // Add newly validated promos to the array to get taxed + const newValidatedPromos = validatePromoResponse?.orderPromos ?? []; + newValidatedPromos.push( + ...(revalidatePromoResponse ? revalidatePromoResponse.promoLineItems : []) ); - lineItemsForCart.vaps = lineItemsForCart.vaps ?? []; - lineItemsForCart.vaps.push(...vapsToAddToCart); - // Tax items on order - lineItemsForCart = await baseMixin.methods.dispatchStoreActionWithLogging( + pricedLineItemsToTax.push(...newValidatedPromos); + // End of promo logic + + const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging( storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA, { billToAccountNumber: store.getters.payment.billToAccountNumber, @@ -284,17 +322,31 @@ export default { serviceLocationCity: store.getters.order.serviceLocation.city, serviceLocationState: store.getters.order.serviceLocation.state, serviceLocationZipCode: store.getters.order.serviceLocation.zipCode, - pricedLineItems: lineItemsForCart, + pricedLineItems: pricedLineItemsToTax, }, "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 = pricedAvailableVaps; - vm.lineItems = lineItemsForCart; + vm.availableVaps = taxedVaps; + vm.lineItems = lineItems; vm.inactivePromos = removeCurrentlyActivePromoCodesFromInactivePromos( vm.lineItems.promos, vm.inactivePromos @@ -589,22 +641,6 @@ export default { this.pageName ); }, - async reTaxItemsOnOrder() { - 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(); }, @@ -825,6 +861,7 @@ export default { ) { return; } + if (oldValue.promos.length < newValue.promos.length) { const oldPromoCodes = oldValue.promos.map( (promoObject) => promoObject.promoCode diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 8bab96d5f..c76222cac 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -65,7 +65,6 @@ pageName="quote" :taxPromos="false" :useDefaultCashParentAccount="true" - @promoAdded="promoAdded" modalWidgetName="PromoModalWidget" /> @@ -577,6 +576,9 @@ export default { isInsuranceContinueButtonText() { return this.getCmsContent("isInsuranceContinueButtonText", "Text"); }, + lineItemsCloneForWatcher() { + return Object.assign({}, this.lineItems); + }, isRecalibrationOnOrder() { return store.getters.isRecalibrationOnOrder; }, @@ -852,9 +854,31 @@ export default { await this.forwardButtonAction(); } }, - promoAdded(lineItems) { - const alert = createPromoSuccessAlert(lineItems.promos[0].promoCode); - this.$refs.funnelHeader.pushGlobalAlert(alert, alert.shouldAutoFade); + }, + 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, }, }, components: { diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 7c9d9f444..716c819e2 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -460,47 +460,111 @@ export default { }; }, async beforeRouteEnter(to, from, next) { - const serviceZipCode = store.getters.order.serviceLocation.zipCode; + const isPricingByDayExperiment = experimentMixin.methods.hasSettingEqualTo( + experimentSettings.PRICING_BY_DAY, + "true" + ); + const showPricingByDay = !store.getters.payment.isInsurance && isPricingByDayExperiment; + // 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, - "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 - ); - } + to.name ); + 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 = [ { @@ -511,6 +575,18 @@ export default { resultKey: "alertReasons", promise: alertReasonsPromise, }, + { + resultKey: "pricingByDayUpchargePart", + promise: pricingByDayUpchargePartPromise, + }, + { + resultKey: "premiumFeeWithPrice", + promise: premiumFeeWithPricePromise, + }, + { + resultKey: "zipCodeData", + promise: zipCodeDataPromise, + }, { resultKey: "mobileFeePart", promise: mobileFeePartPromise, @@ -519,70 +595,39 @@ 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); - } - 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"; - } - } + // add pricing by day data + const pricingByDayUpcharge = + showPricingByDay && resultMap.pricingByDayUpchargePart + ? await baseMixin.methods.getTotalLineItemPrice( + resultMap.pricingByDayUpchargePart, + false + ) + : null; // 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 = pricedPremiumFee; + vm.mobilePremiumAppointmentFee = resultMap.premiumFeeWithPrice + ? resultMap.premiumFeeWithPrice[0] + : null; vm.updateFooterButtonText(vm.selectedTimeSlotInfo); - 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.pricingByDayUpchargeLineItem = resultMap.pricingByDayUpchargePart; + vm.includePricingByDayUpcharge = includePricingByDayUpcharge; + vm.isPricingByDayExperiment = isPricingByDayExperiment; + vm.pricingByDayBasePrice = pricingByDayBasePrice; + vm.pricingByDayUpcharge = pricingByDayUpcharge; + vm.showPricingByDay = showPricingByDay; vm.preSelectedDate = preSelectedDate; vm.appointmentType = appointmentType; vm.setData( - zipCodeData, + resultMap.zipCodeData, resultMap.serviceabilityDetails, - pricedMobileFeePart, + resultMap.mobileFeePart, shopProviderData.data ); vm.initializeDatePicker(); diff --git a/src/store/index.js b/src/store/index.js index 1fa9b4f14..402ff212f 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2958,14 +2958,8 @@ export const actions = { pageNameToLog, } ) { - const arrayOfLineItems = [ - ...(pricedLineItems.glassParts ?? []), - ...(pricedLineItems.promos ?? []), - ...(pricedLineItems.supportingItems ?? []), - ...(pricedLineItems.vaps ?? []), - ]; const flattenedLineItemsWithChildParts = - getFlattenedArrayOfLineItemsWithChildParts(arrayOfLineItems); + getFlattenedArrayOfLineItemsWithChildParts(pricedLineItems); const lineItemsWithOnlyPriceInfo = flattenedLineItemsWithChildParts.map((lineItem) => ({ partNumber: lineItem.partNumber, @@ -3014,12 +3008,8 @@ export const actions = { }); context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData); - Object.keys(pricedLineItems).forEach((key) => { - pricedLineItems[key] = addTaxesToPricedLineItems( - pricedLineItems[key] ?? [], - response.data.taxedLineItems - ); - }); + + pricedLineItems = addTaxesToPricedLineItems(pricedLineItems, response.data.taxedLineItems); return pricedLineItems; }, From 5ecd1e5c42ed0df90c060abf6d8545d7d05a8963 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 22 Oct 2025 14:58:36 -0400 Subject: [PATCH 12/12] Redo rain repel changes --- src/layouts/payment-method/payment-method.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 3f7124f84..2c51f42a1 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -218,8 +218,8 @@ export default { ) : Promise.resolve([]); - const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging( - storeActions.GET_RAIN_DEFENSE, + const rainRepelPromise = baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.GET_RAIN_REPEL, null, "payment-method" ); @@ -265,7 +265,7 @@ export default { []); const allLineItems = [ - resultMap.rainDefense, + resultMap.rainRepel, ...supportingItems, ...availableFrontWipers, ...availableRearWipers, @@ -278,7 +278,7 @@ export default { ); const availableVaps = [ - resultMap.rainDefense, + resultMap.rainRepel, ...availableFrontWipers, ...availableRearWipers, ];