CASH-152: Refactor - move cart- and payment- related helpers out of base mixin

This commit is contained in:
Adam Caouette 2025-03-06 16:27:09 -05:00
parent 914c187086
commit 46555cbaf9
10 changed files with 166 additions and 242 deletions

View file

@ -173,6 +173,12 @@ import {
} from "@/helpers/service-package-helper";
import { getPromoCodeWithoutBundleIdentifier } from "@/helpers/promotions-helper";
import { storeActions } from "@/constants/store-actions";
import {
getDisplayAmountDue,
getAmountDue,
getSubTotal,
getSalesTax,
} from "@/helpers/cart-and-payment-helper.js";
// Constants
import { partTypeStrings } from "@/constants/part-type-strings";
@ -1069,8 +1075,8 @@ export default {
subTotal() {
if (!this.lineItems || this.lineItems.length < 1) return;
return this.isInsurance || !this.shouldHideRecalibration
? baseMixin.methods.getSubTotal(this.lineItems) // calculate with recal (if on order)
: baseMixin.methods.getSubTotal(this.lineItemsWithoutRecal); // calculate without recal
? getSubTotal(this.lineItems) // calculate with recal (if on order)
: getSubTotal(this.lineItemsWithoutRecal); // calculate without recal
},
salesTax() {
if (!this.lineItems || this.lineItems.length < 1) return;
@ -1085,15 +1091,15 @@ export default {
}
return this.isInsurance || !this.shouldHideRecalibration
? baseMixin.methods.getSalesTax(this.lineItems) // calculate with recal (if on order)
: baseMixin.methods.getSalesTax(this.lineItemsWithoutRecal); // calculated without recal
? getSalesTax(this.lineItems) // calculate with recal (if on order)
: getSalesTax(this.lineItemsWithoutRecal); // calculated without recal
},
amountDue() {
if (!this.lineItems || this.lineItems.length < 1) return;
if (this.showAsPaid) return 0;
return this.isInsurance || !this.shouldHideRecalibration
? baseMixin.methods.getAmountDue(this.lineItems) // calculate with recal (if on order)
: baseMixin.methods.getAmountDue(this.lineItemsWithoutRecal); // calculated without recal
? getAmountDue(this.lineItems) // calculate with recal (if on order)
: getAmountDue(this.lineItemsWithoutRecal); // calculated without recal
},
amountPaid() {
if (!this.showAsPaid) {

View file

@ -0,0 +1,56 @@
import store from "@/store";
import baseMixin from "@/mixins/base-mixin.js";
export function getDisplayAmountDue(lineItems) {
// lineItems s/b an OBJECT here (not flattened) FROM PAYMENT
return getAmountDue(lineItems).toLocaleString("en-US", {
style: "currency",
currency: "USD",
});
}
export function getAmountDue(lineItems, includeTax = true) {
// lineItems s/b an OBJECT here (not flattened) FROM CART, PAYMENT PAGES
var amountDue = 0;
if (lineItems?.glassParts) {
amountDue += baseMixin?.methods?.getTotalPriceOfAllLineItemsAndChildParts(
lineItems.glassParts,
includeTax
);
}
if (lineItems?.supportingItems) {
amountDue += baseMixin?.methods?.getTotalPriceOfAllLineItemsAndChildParts(
lineItems.supportingItems,
includeTax
);
}
const order = baseMixin?.methods?.hasSubmittedOrder() ? baseMixin?.methods?.getSubmittedOrder() : store.getters.order;
if (store.getters.coverageIsVerified && !order.policy.isNoComp && !order.policy.isItac) {
amountDue = order.policy.currentDeductible;
}
if (lineItems?.vaps) {
amountDue += baseMixin?.methods?.getTotalPriceOfAllLineItemsAndChildParts(lineItems.vaps, includeTax);
}
if (lineItems?.promos) {
amountDue += baseMixin?.methods?.getTotalPriceOfAllLineItemsAndChildParts(lineItems.promos, includeTax);
}
return ((amountDue * 100) / 100).toFixed(2);
}
export function getSubTotal(lineItems) {
// this is amountDue without sales tax
// lineItems s/b an OBJECT here (not flattened) USED IN CART
// can be an ARRAY (flattened) FROM QUOTE
return getAmountDue(lineItems, false);
}
export function getSalesTax(lineItems) {
// this is amountDue minus subTotal
// lineItems s/b an OBJECT here (not flattened) USED IN CART
return (((getAmountDue(lineItems) - getSubTotal(lineItems)) * 100) / 100).toFixed(2);
}

View file

@ -0,0 +1,66 @@
import {
getDisplayAmountDue,
getAmountDue,
getSubTotal,
getSalesTax,
} from "@/helpers/cart-and-payment-helper.js";
const lineItems = {
glassParts: [],
supportingItems: [],
vaps: [
{
cartItemType: "FRONT WIPERS",
description: 'WIPER BLADE STANDARD 18"',
kitPrice: 0,
laborAmount: 0,
partNumber: "WB18",
partType: "FRONT WIPER",
salesTax: 2.0,
sellingPrice: 30.0,
},
{
cartItemType: "FRONT WIPERS",
description: 'WIPER BLADE STANDARD 26"',
kitPrice: 0,
laborAmount: 0,
partNumber: "WB26",
partType: "FRONT WIPER",
salesTax: 1.0,
sellingPrice: 20.0,
},
],
promos: [],
};
describe('cart-and-payment-helper', () => {
describe('getDisplayAmountDue', () => {
it('should return the correct display amount due', () => {
const result = getDisplayAmountDue(lineItems);
expect(result).toBe('53.00');
});
});
describe('getAmountDue', () => {
it('should return the correct amount due', () => {
const result = getAmountDue(lineItems, true);
expect(result).toBe('53.00');
});
});
describe('getSubTotal', () => {
it('should return the correct subtotal', () => {
const result = getSubTotal(lineItems);
expect(result).toBe('50.00');
});
});
describe('getSalesTax', () => {
it('should return the correct sales tax', () => {
const result = getSalesTax(lineItems);
expect(result).toBe('3.00');
});
});
});

View file

@ -16,6 +16,10 @@ jest.mock("@/helpers/heritage-integration/order-helper.js", () => ({
submitWorkOrder: jest.fn(),
}));
jest.mock("@/helpers/cart-and-payment-helper.js", () => ({
getAmountDue: jest.fn(),
}));
let piaDisabledFlag = false;
describe("payment-method.vue", () => {

View file

@ -157,6 +157,12 @@ 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 {
getDisplayAmountDue,
getAmountDue,
getSubTotal,
getSalesTax,
} from "@/helpers/cart-and-payment-helper.js";
defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED));
defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED));
@ -765,7 +771,7 @@ export default {
);
},
totalAmountDue() {
return baseMixin.methods.getAmountDue(this.lineItems);
return getAmountDue(this.lineItems);
},
isPiaEnabled() {
const piaExperience = this.getSettingValue(experimentSettings.PIA_EXPERIENCE);

View file

@ -10,11 +10,17 @@ import { queryStrings } from "@/constants/query-strings";
import { getQuerystringParameter } from "@/helpers/querystring-helper";
import { storeActions } from "@/constants/store-actions";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin.js";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import { Form } from "vee-validate";
import { paymentMethods } from "@/constants/payment-method-constants";
import { routerParams } from "@/router/router-constants/router-params";
import baseMixin from "@/mixins/base-mixin.js";
import {
getDisplayAmountDue,
getAmountDue,
getSubTotal,
getSalesTax,
} from "@/helpers/cart-and-payment-helper.js";
export default {
name: "payment-pia-return",
@ -159,7 +165,7 @@ export default {
}
},
getAmountDue() {
return baseMixin.methods.getAmountDue(store.getters.order.lineItems);
return getAmountDue(store.getters.order.lineItems);
},
async saveAndSubmitWorkOrder() {
// Final work order submit after returning from PIA.

View file

@ -5,10 +5,14 @@ import payment from "@/layouts/payment/payment";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin";
import { storeActions } from "@/constants/store-actions";
import { paymentMethods } from "@/constants/payment-method-constants";
jest.mock("@/helpers/cart-and-payment-helper.js", () => ({
getAmountDue: jest.fn(),
getDisplayAmountDue: jest.fn(),
}));
// Constants
const parts = {
windshield: {

View file

@ -234,6 +234,12 @@ import iframeResize from "../../../node_modules/iframe-resizer/js/iframeResizer.
import { routerParams } from "@/router/router-constants/router-params";
import { coverageStatus } from "@/constants/insurance";
import { getBoolFromString } from "@/helpers/boolean-helper.js";
import {
getDisplayAmountDue,
getAmountDue,
getSubTotal,
getSalesTax,
} from "@/helpers/cart-and-payment-helper.js";
export default {
name: "payment",
@ -656,10 +662,10 @@ export default {
this.piaLineItems = lineItems.join("||");
},
getAmountDue() {
return baseMixin.methods.getAmountDue(store.getters.order.lineItems);
return getAmountDue(store.getters.order.lineItems);
},
getDisplayAmountDue() {
return baseMixin.methods.getDisplayAmountDue(store.getters.order.lineItems);
return getDisplayAmountDue(store.getters.order.lineItems);
},
async paymentFailedPayLater() {
this.$refs.loadingModal.isModalVisible = true;

View file

@ -144,64 +144,7 @@ export default {
return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice;
}
},
getDisplayAmountDue(lineItems) {
return this.getAmountDue(lineItems).toLocaleString("en-US", {
style: "currency",
currency: "USD",
});
},
getAmountDue(lineItems, includeTax = true) {
var amountDue = 0;
if (lineItems?.glassParts) {
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
lineItems.glassParts,
includeTax
);
}
if (lineItems?.supportingItems) {
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
lineItems.supportingItems,
includeTax
);
}
const order = this.hasSubmittedOrder() ? this.getSubmittedOrder() : store.getters.order;
if (
store.getters.coverageIsVerified &&
!order.policy.isNoComp &&
!order.policy.isItac
) {
amountDue = order.policy.currentDeductible;
}
if (lineItems?.vaps) {
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
lineItems.vaps,
includeTax
);
}
if (lineItems?.promos) {
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
lineItems.promos,
includeTax
);
}
return ((amountDue * 100) / 100).toFixed(2);
},
getSubTotal(lineItems) {
// this is amountDue without sales tax
return this.getAmountDue(lineItems, false);
},
getSalesTax(lineItems) {
// this is amountDue minus subTotal
return (
((this.getAmountDue(lineItems) - this.getSubTotal(lineItems)) * 100) /
100
).toFixed(2);
},
scrollToPageTop() {
const container = document.getElementsByClassName("page-container-grouped-styles")[0];
container.scrollTo({ top: 0, left: 0, behavior: "smooth" });

View file

@ -145,179 +145,6 @@ describe("baseMixin.js", () => {
expect(mixIn.methods.dispatchStoreActionWithLogging).toBeCalled();
});
test("getAmountDue for verified deductible should be deductible plus any lineitems", () => {
const mixIn = getMixInInstance({});
const lineItems = {
glassParts: [],
supportingItems: [],
vaps: [
{
cartItemType: "FRONT WIPERS",
description: 'WIPER BLADE STANDARD 18"',
kitPrice: 0,
laborAmount: 0,
partNumber: "WB18",
partType: "FRONT WIPER",
salesTax: 2.0,
sellingPrice: 30.0,
},
{
cartItemType: "FRONT WIPERS",
description: 'WIPER BLADE STANDARD 26"',
kitPrice: 0,
laborAmount: 0,
partNumber: "WB26",
partType: "FRONT WIPER",
salesTax: 1.0,
sellingPrice: 20.0,
},
],
promos: [],
};
const payment = { insuranceCoverage: { isVerified: false } };
const policy = { isNoComp: false, isItac: false, currentDeductible: 250 };
store.getters = {
payment: payment,
policy: policy,
order: {
payment: payment,
policy: policy,
},
hasSubmittedOrder: false,
};
var amtDue = mixIn.methods.getAmountDue(lineItems);
expect(amtDue).toEqual("53.00");
});
test("getAmountDue should function with a submitted order", () => {
const mixIn = getMixInInstance({});
const lineItems = {
glassParts: [],
supportingItems: [],
vaps: [
{
cartItemType: "FRONT WIPERS",
description: 'WIPER BLADE STANDARD 18"',
kitPrice: 0,
laborAmount: 0,
partNumber: "WB18",
partType: "FRONT WIPER",
salesTax: 2.0,
sellingPrice: 30.0,
},
{
cartItemType: "FRONT WIPERS",
description: 'WIPER BLADE STANDARD 26"',
kitPrice: 0,
laborAmount: 0,
partNumber: "WB26",
partType: "FRONT WIPER",
salesTax: 1.0,
sellingPrice: 20.0,
},
],
promos: [],
};
const payment = { insuranceCoverage: { isVerified: false } };
const policy = { isNoComp: false, isItac: false, currentDeductible: 250 };
mixIn.methods.hasSubmittedOrder = jest.fn().mockReturnValue(true);
mixIn.methods.getSubmittedOrder = jest.fn().mockReturnValue({
payment: payment,
policy: policy,
});
store.getters = {
payment: {},
policy: {},
order: {},
};
var amtDue = mixIn.methods.getAmountDue(lineItems);
expect(amtDue).toEqual("53.00");
});
test("getAmountDue for cash should sum lineitems", () => {
const mixIn = getMixInInstance({});
const lineItems = {
glassParts: [
{
partNumber: "FW06143GTYN",
description:
"solar, heads-up display, third visor frit, soundproofing, rain/light sensor, lane departure warning system",
color: "Green Tint",
partType: "WINDSHIELD",
canSafeliteRecalibrate: true,
requiresRecalibration: true,
requiresCapabilityQuestions: false,
recalibrationType: "STATIC",
childParts: [
{
partNumber: "RS 101 PAD",
kitPrice: 0,
laborAmount: 0,
salesTax: 5.0,
sellingPrice: 5.0,
},
],
id: "73e80976-79be-455a-b4e7-f9b058b61749",
kitPrice: 0,
laborAmount: 60,
salesTax: 20.0,
sellingPrice: 1000.0,
},
],
supportingItems: [],
vaps: [
{
cartItemType: "FRONT WIPERS",
description: 'WIPER BLADE STANDARD 18"',
kitPrice: 0,
laborAmount: 0,
partNumber: "WB18",
partType: "FRONT WIPER",
salesTax: 2.0,
sellingPrice: 30.0,
},
{
cartItemType: "FRONT WIPERS",
description: 'WIPER BLADE STANDARD 26"',
kitPrice: 0,
laborAmount: 0,
partNumber: "WB26",
partType: "FRONT WIPER",
salesTax: 1.0,
sellingPrice: 20.0,
},
],
promos: [],
};
const payment = { isInsurance: null, insuranceCoverage: { isVerified: null } };
const policy = { isNoComp: false, isItac: false, currentDeductible: 0 };
mixIn.methods.hasSubmittedOrder = jest.fn().mockReturnValue(false);
store.getters = {
payment: payment,
policy: policy,
order: {
payment: payment,
policy: policy,
},
hasSubmittedOrder: false,
};
var amtDue = mixIn.methods.getAmountDue(lineItems);
expect(amtDue).toEqual("1143.00");
});
});
function getMixInInstance({ isDispatchSuccess = true }) {