From 2bfd1f65ac1d06d36e05209bae4adda19bf076f7 Mon Sep 17 00:00:00 2001 From: Minojhini Valaiyapathi Date: Thu, 18 Sep 2025 14:31:27 -0400 Subject: [PATCH 1/4] CASH-1428 - Recalculate Pricing and Tax with line items from store --- src/layouts/payment-method/payment-method.vue | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index db5ccdced..75173bc82 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -488,6 +488,46 @@ export default { getInactivePromosFromStore() { return this.$store.getters.order.payment.inactivePromos; }, + async getCalcOrderAndTaxedLineItems(lineItemsToTax) { + const lineItemsFromStore = deepClone(store.getters.order.lineItems); + const pricedLineItemsToTax = await baseMixin.methods.dispatchStoreActionWithLogging( + storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA, + { + availableLineItems: lineItemsToTax, + }, + "payment-method", + false + ); + const promoCodeFromQueryString = consumeQueryFromStash(queryStrings.PROMO); + const { validatePromoResponse, revalidatePromoResponse } = + await revalidatePromosAndValidateQueryStringPromo( + promoCodeFromQueryString, + pricedLineItemsToTax, + "payment-method" + ); + + const newValidatedPromos = validatePromoResponse?.orderPromos ?? []; + newValidatedPromos.push( + ...(revalidatePromoResponse ? revalidatePromoResponse.promoLineItems : []) + ); + pricedLineItemsToTax.push(...newValidatedPromos); + + const taxedLineItems = 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: pricedLineItemsToTax, + }, + "payment-method", + false + ); + return mapTaxedLineItemsToStoreFormat(taxedLineItems, lineItemsFromStore); + }, async revalidatePromos() { this.$refs.loadingModal.showModal(); const revalidatePromoResponse = await baseMixin.methods.dispatchStoreActionWithLogging( @@ -574,22 +614,32 @@ export default { this.paymentMethod, false ); + + // recalulate pricing and tax with line items from store + const lineItemsFromStore = deepClone(store.getters.order.lineItems); + const lineItemsToTax = [ + ...(lineItemsFromStore.glassParts ?? []), + ...(lineItemsFromStore.supportingItems ?? []), + ...(lineItemsFromStore.vaps ?? []), + ]; + const taxedLineItems = await this.getCalcOrderAndTaxedLineItems(lineItemsToTax); + // save lineitems as they now have salestax added await this.dispatchStoreAction( storeActions.SAVE_GLASS_PARTS_SUPPRESSING_STATE_RESETTING, - this.lineItems.glassParts, + taxedLineItems.glassParts, false ); await this.dispatchStoreAction( storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING, - this.lineItems.supportingItems, + taxedLineItems.supportingItems, false ); - await this.dispatchStoreAction(storeActions.SAVE_VAPS, this.lineItems.vaps, false); + await this.dispatchStoreAction(storeActions.SAVE_VAPS, taxedLineItems.vaps, false); this.dispatchStoreAction( storeActions.SAVE_ACTIVE_AND_OR_INACTIVE_PROMOS, { - activePromos: this.lineItems.promos, + activePromos: taxedLineItems.promos, inactivePromos: this.inactivePromos, }, false From af0f9c2bd854c3c46b241bafd41af13a0bb9c271 Mon Sep 17 00:00:00 2001 From: Minojhini Valaiyapathi Date: Thu, 18 Sep 2025 18:33:10 -0400 Subject: [PATCH 2/4] CASH-1428 - Fixed unit test --- src/layouts/payment-method/payment-method.spec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/layouts/payment-method/payment-method.spec.js b/src/layouts/payment-method/payment-method.spec.js index 3e31f88c5..786b24036 100644 --- a/src/layouts/payment-method/payment-method.spec.js +++ b/src/layouts/payment-method/payment-method.spec.js @@ -7,6 +7,9 @@ import { getMountOptions } from "@/helpers/unit-test-helper.js"; import store from "@/store"; import { experimentSettings } from "@/constants/experiments"; +global.crypto = { + randomUUID: jest.fn() +}; // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ settleAllPromises: jest.fn(), @@ -81,7 +84,10 @@ function setupMocks() { city: "Anytown", state: "OH", zipCode: "00000", + provider: { providerNumber: "0000567"} }, + vehicle: { year: 2020, make: "Toyota", model: "Camry", carId:"12345" }, + damage: {isRepair: false} }, policy: { currentDeductible: 123, From e8f5bc9e246afc0f2ff26676fe88e6443833819d Mon Sep 17 00:00:00 2001 From: Minojhini Valaiyapathi Date: Thu, 18 Sep 2025 18:36:35 -0400 Subject: [PATCH 3/4] CASH-1428 - Ran format --- src/layouts/payment-method/payment-method.spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/layouts/payment-method/payment-method.spec.js b/src/layouts/payment-method/payment-method.spec.js index 786b24036..eda6777cb 100644 --- a/src/layouts/payment-method/payment-method.spec.js +++ b/src/layouts/payment-method/payment-method.spec.js @@ -8,7 +8,7 @@ import store from "@/store"; import { experimentSettings } from "@/constants/experiments"; global.crypto = { - randomUUID: jest.fn() + randomUUID: jest.fn(), }; // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ @@ -84,10 +84,10 @@ function setupMocks() { city: "Anytown", state: "OH", zipCode: "00000", - provider: { providerNumber: "0000567"} + provider: { providerNumber: "0000567" }, }, - vehicle: { year: 2020, make: "Toyota", model: "Camry", carId:"12345" }, - damage: {isRepair: false} + vehicle: { year: 2020, make: "Toyota", model: "Camry", carId: "12345" }, + damage: { isRepair: false }, }, policy: { currentDeductible: 123, From e8d7ee5353ad6b48e2ef6ef02c197277b3bdea2b Mon Sep 17 00:00:00 2001 From: Minojhini Valaiyapathi Date: Thu, 18 Sep 2025 20:51:59 -0400 Subject: [PATCH 4/4] CASH-1428 - Fixed unit test --- .../payment-method/payment-method.spec.js | 153 ++++++++++++++++-- 1 file changed, 143 insertions(+), 10 deletions(-) diff --git a/src/layouts/payment-method/payment-method.spec.js b/src/layouts/payment-method/payment-method.spec.js index eda6777cb..b59c08279 100644 --- a/src/layouts/payment-method/payment-method.spec.js +++ b/src/layouts/payment-method/payment-method.spec.js @@ -6,10 +6,16 @@ import { shallowMount } from "@vue/test-utils"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; import store from "@/store"; import { experimentSettings } from "@/constants/experiments"; +import { storeMutations } from "@/constants/store-mutations"; +import globalMethods from "@/global-methods"; + +globalMethods.callHttpClient = jest.fn(); + +global.crypto = { randomUUID: jest.fn() }; +const mockPriceOrderItemsAndSaveServerData = jest + .fn() + .mockResolvedValue(/* your mock return value */); -global.crypto = { - randomUUID: jest.fn(), -}; // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ settleAllPromises: jest.fn(), @@ -37,16 +43,140 @@ describe("payment-method.vue", () => { // Assert expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); }); + }); - test("if the continue button is clicked, navigate forward", async () => { - // Arrange - const { wrapper } = setupMocks(); + describe("forwardButtonAction", () => { + let wrapper; + let mockDispatchStoreAction; + let mockGetCalcOrderAndTaxedLineItems; + let mockSubmitWorkOrder; + let mockRouter; + let mockLoadingModal; + let mockStoreGetters; + let mockLineItems; + let mockInactivePromos; + let mockIsRecalAckOptIn; + let mockPaymentMethod; + let mockPaymentMethods; - // Act - await wrapper.vm.forwardButtonAction(); + beforeEach(() => { + mockDispatchStoreAction = jest.fn().mockResolvedValue(); + mockGetCalcOrderAndTaxedLineItems = jest.fn().mockResolvedValue({ + glassParts: [], + supportingItems: [], + vaps: [], + promos: [], + }); + mockSubmitWorkOrder = jest.fn().mockResolvedValue(); + mockRouter = { + navigateWithoutSaving: jest.fn(), + navigateWithSaving: jest.fn(), + }; + mockLoadingModal = { showModal: jest.fn(), hideModal: jest.fn() }; + mockStoreGetters = { + order: { + lineItems: { + glassParts: [], + supportingItems: [], + vaps: [], + }, + payment: { isInsurance: false, piaType: null, isPia: false }, + serviceLocation: { + provider: { providerNumber: "0000567" }, + appointmentType: "Mobile", + city: "Anytown", + state: "OH", + zipCode: "00000", + }, + schedule: { + date: "2024-01-01", + startTime: "09:00", + endTime: "10:00", + jobMaxMinutes: 60, + jobMinMinutes: 60, + }, + customer: { + firstName: "Test", + lastName: "User", + phoneNumber: "555-555-5555", + emailAddress: "test@example.com", + }, + policy: { currentDeductible: 123, isNoComp: false, isItac: false }, + }, + payment: { insuranceCoverage: { coverageStatus: "VERIFIED" } }, + policy: { currentDeductible: 123 }, + }; + mockLineItems = { glassParts: [], supportingItems: [], vaps: [], promos: [] }; + mockInactivePromos = []; + mockIsRecalAckOptIn = false; + mockPaymentMethod = "LATER"; + mockPaymentMethods = { LATER: "LATER", INSURANCE: "INSURANCE" }; - // Assert - expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); + wrapper = { + $refs: { loadingModal: mockLoadingModal }, + $router: mockRouter, + $store: { getters: mockStoreGetters }, + dispatchStoreAction: mockDispatchStoreAction, + getCalcOrderAndTaxedLineItems: mockGetCalcOrderAndTaxedLineItems, + lineItems: mockLineItems, + inactivePromos: mockInactivePromos, + isRecalAckOptIn: mockIsRecalAckOptIn, + paymentMethod: mockPaymentMethod, + paymentMethods: mockPaymentMethods, + storeActions: require("@/constants/store-actions"), + navigationScenarios: { + CLICKED_FORWARD: "CLICKED_FORWARD", + CLICKED_INSURANCE: "CLICKED_INSURANCE", + CLICKED_PAY_NOW: "CLICKED_PAY_NOW", + }, + pageName: "payment-method", + setupPia: jest.fn(), + customCtaCopy: "Continue", + }; + + jest.mock("@/helpers/heritage-integration/order-helper.js", () => ({ + submitWorkOrder: mockSubmitWorkOrder, + })); + }); + + it("should call all expected methods and navigate when paymentMethod is LATER", async () => { + wrapper.paymentMethod = mockPaymentMethods.LATER; + const submitWorkOrder = + require("@/helpers/heritage-integration/order-helper.js").submitWorkOrder; + await require("@/layouts/payment-method/payment-method.vue").default.methods.forwardButtonAction.call( + wrapper + ); + expect(mockLoadingModal.showModal).toHaveBeenCalled(); + expect(mockDispatchStoreAction).toHaveBeenCalledWith( + "savePaymentMethodChoice", + wrapper.paymentMethod, + false + ); + expect(mockGetCalcOrderAndTaxedLineItems).toHaveBeenCalled(); + expect(mockDispatchStoreAction).toHaveBeenCalledWith( + "saveGlassPartsSuppressingStateResetting", + mockLineItems.glassParts, + false + ); + expect(mockDispatchStoreAction).toHaveBeenCalledWith( + "saveSupportingItemsSuppressingStateResetting", + mockLineItems.supportingItems, + false + ); + expect(mockDispatchStoreAction).toHaveBeenCalledWith( + "saveVaps", + mockLineItems.vaps, + false + ); + expect(mockDispatchStoreAction).toHaveBeenCalledWith( + "saveActiveAndOrInactivePromos", + { activePromos: mockLineItems.promos, inactivePromos: mockInactivePromos }, + false + ); + expect(mockDispatchStoreAction).toHaveBeenCalledWith( + "saveIsRecalAckOptIn", + mockIsRecalAckOptIn + ); }); }); }); @@ -107,6 +237,9 @@ function setupMocks() { store: { getters: store.getters, }, + actions: { + priceOrderItemsAndSaveServerData: mockPriceOrderItemsAndSaveServerData, + }, }); const mockMixin = {