commit
86f2fcd311
19 changed files with 1386 additions and 856 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
const partTypeStrings = Object.freeze({
|
const partTypeStrings = Object.freeze({
|
||||||
|
WINDSHIELD: 'WINDSHIELD',
|
||||||
FRONT_WIPER: 'FRONT WIPER',
|
FRONT_WIPER: 'FRONT WIPER',
|
||||||
REAR_WIPER: 'REAR WIPER',
|
REAR_WIPER: 'REAR WIPER',
|
||||||
RAIN_DEFENSE: 'RAIN DEFENSE',
|
RAIN_DEFENSE: 'RAIN DEFENSE',
|
||||||
|
|
|
||||||
143
src/helpers/cart-helper.js
Normal file
143
src/helpers/cart-helper.js
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
import { useMainStore } from '@/store';
|
||||||
|
import { getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator';
|
||||||
|
import partNumberStrings from '@/constants/part-number-strings';
|
||||||
|
import partTypeStrings from '@/constants/part-type-strings';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the lineItems object from the order
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {object} lineItems object from the order
|
||||||
|
*/
|
||||||
|
export function getLineItems(order) {
|
||||||
|
return order.lineItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array containing only the service line items
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {[]} array of service line items
|
||||||
|
*/
|
||||||
|
export function getServiceLineItems(order) {
|
||||||
|
const { supportingItems, glassParts, otherParts } = getLineItems(order);
|
||||||
|
return [
|
||||||
|
...(supportingItems ?? []),
|
||||||
|
...(glassParts ?? []),
|
||||||
|
...(otherParts ?? [])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array containing only the non-service line items (Vaps and Fees)
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {[]} array of non-service line items
|
||||||
|
*/
|
||||||
|
export function getNonServiceLineItems(order) {
|
||||||
|
const { vaps, feeItems } = getLineItems(order);
|
||||||
|
return [
|
||||||
|
...(vaps ?? []),
|
||||||
|
...(feeItems ?? [])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array containing all line items
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {[]} array of all line items
|
||||||
|
*/
|
||||||
|
export function getAllLineItems(order) {
|
||||||
|
return [
|
||||||
|
...getServiceLineItems(order),
|
||||||
|
...getNonServiceLineItems(order)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the recycle fee line item if it exists on the order
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {{}|undefined} recycle fee line item or undefined
|
||||||
|
*/
|
||||||
|
export function getRecycleFeeLineItem(order) {
|
||||||
|
return getLineItems(order).feeItems?.find((lineItem) => lineItem.partNumber === partNumberStrings.RECYCLE_FEE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mobile fee line item if it exists on the order
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {{}|undefined} mobile fee line item or undefined
|
||||||
|
*/
|
||||||
|
export function getMobileFeeLineItem(order) {
|
||||||
|
return getLineItems(order).feeItems?.find((lineItem) => lineItem.partType === partTypeStrings.MOBILE_FEE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current deductible on the order
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {number|undefined|null} current deductible
|
||||||
|
*/
|
||||||
|
export function getDeductible(order) {
|
||||||
|
return order.currentDeductible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the order is unverified
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {boolean} order unverified state
|
||||||
|
*/
|
||||||
|
export function isOrderUnverified(order) {
|
||||||
|
return order.isUnverified ?? useMainStore().isUnverified;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the order is NO COMP
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {boolean} order NO COMP flag
|
||||||
|
*/
|
||||||
|
export function isOrderNoComp(order) {
|
||||||
|
return order.policy?.noCoverage ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the order is ITAC
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {boolean} order ITAC flag
|
||||||
|
*/
|
||||||
|
export function isOrderITAC(order) {
|
||||||
|
return order.policy?.isITAC ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the subtotal for the order
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {number} sub total for the order
|
||||||
|
*/
|
||||||
|
export function getSubtotal(order) {
|
||||||
|
if (!isOrderUnverified(order) && !isOrderNoComp(order) && !isOrderITAC(order)) {
|
||||||
|
return getDeductible(order) + getPriceOfLineItems(getNonServiceLineItems(order));
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPriceOfLineItems(getAllLineItems(order));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sales tax for the order
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {number} sales tax for the order
|
||||||
|
*/
|
||||||
|
export function getSalesTax(order) {
|
||||||
|
let tax = 0;
|
||||||
|
if (!isOrderUnverified(order) && (isOrderITAC(order) || isOrderNoComp(order))) {
|
||||||
|
tax += getTaxOfLineItems(getServiceLineItems(order));
|
||||||
|
}
|
||||||
|
|
||||||
|
tax += getTaxOfLineItems(getNonServiceLineItems(order));
|
||||||
|
return tax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cart total rounded to two decimal places
|
||||||
|
* @param {object} order order object
|
||||||
|
* @returns {number} cart total for the order
|
||||||
|
*/
|
||||||
|
export function getCartTotal(order) {
|
||||||
|
return Math.round((getSubtotal(order) + getSalesTax(order)) * 100) / 100;
|
||||||
|
}
|
||||||
602
src/helpers/cart-helper.spec.js
Normal file
602
src/helpers/cart-helper.spec.js
Normal file
|
|
@ -0,0 +1,602 @@
|
||||||
|
import {
|
||||||
|
getAllLineItems,
|
||||||
|
getCartTotal,
|
||||||
|
getDeductible,
|
||||||
|
getLineItems,
|
||||||
|
getMobileFeeLineItem, getNonServiceLineItems,
|
||||||
|
getRecycleFeeLineItem, getSalesTax,
|
||||||
|
getServiceLineItems, getSubtotal, isOrderITAC, isOrderNoComp,
|
||||||
|
isOrderUnverified
|
||||||
|
} from '@/helpers/cart-helper';
|
||||||
|
import partTypeStrings from '@/constants/part-type-strings';
|
||||||
|
import partNumberStrings from '@/constants/part-number-strings';
|
||||||
|
|
||||||
|
describe('cart-helper', () => {
|
||||||
|
function createDummyItem(partNumber, price, salesTax) {
|
||||||
|
return {
|
||||||
|
partNumber,
|
||||||
|
sellingPrice: price,
|
||||||
|
kitPrice: 0,
|
||||||
|
laborAmount: 0,
|
||||||
|
salesTax
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDummyFeeItem(partNumber, partType, price, salesTax) {
|
||||||
|
return {
|
||||||
|
partNumber,
|
||||||
|
partType,
|
||||||
|
sellingPrice: price,
|
||||||
|
kitPrice: 0,
|
||||||
|
laborAmount: 0,
|
||||||
|
salesTax
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const nullLineItems = {
|
||||||
|
supportingItems: null,
|
||||||
|
glassParts: null,
|
||||||
|
otherParts: null,
|
||||||
|
vaps: null,
|
||||||
|
feeItems: null
|
||||||
|
};
|
||||||
|
|
||||||
|
const emptyLineItems = {
|
||||||
|
supportingItems: [],
|
||||||
|
glassParts: [],
|
||||||
|
otherParts: [],
|
||||||
|
vaps: [],
|
||||||
|
feeItems: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const supportingLineItem = createDummyItem('supporting', 30, 1);
|
||||||
|
const glassLineItem = createDummyItem('glass', 40, 2);
|
||||||
|
const otherLineItem = createDummyItem('other', 50, 3);
|
||||||
|
const vapsLineItem = createDummyItem('vaps', 60, 4);
|
||||||
|
const mobileFeeLineItem = createDummyFeeItem(null, partTypeStrings.MOBILE_FEE, 70, 5);
|
||||||
|
const recycleFeeLineItem = createDummyFeeItem(partNumberStrings.RECYCLE_FEE, null, 80, 6);
|
||||||
|
|
||||||
|
const defaultLineItems = {
|
||||||
|
supportingItems: [supportingLineItem],
|
||||||
|
glassParts: [glassLineItem],
|
||||||
|
otherParts: [otherLineItem],
|
||||||
|
vaps: [vapsLineItem],
|
||||||
|
feeItems: [mobileFeeLineItem, recycleFeeLineItem]
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('getLineItems', () => {
|
||||||
|
test('Returns line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: emptyLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getLineItems(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toMatchObject(order.lineItems);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getServiceLineItems', () => {
|
||||||
|
test('Returns only service line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getServiceLineItems(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toHaveLength(3);
|
||||||
|
expect(result).toContain(supportingLineItem);
|
||||||
|
expect(result).toContain(glassLineItem);
|
||||||
|
expect(result).toContain(otherLineItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns empty array when line items are null', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: nullLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getServiceLineItems(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getNonServiceLineItems', () => {
|
||||||
|
test('Returns only service line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getNonServiceLineItems(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toHaveLength(3);
|
||||||
|
expect(result).toContain(vapsLineItem);
|
||||||
|
expect(result).toContain(mobileFeeLineItem);
|
||||||
|
expect(result).toContain(recycleFeeLineItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns empty array when line items are null', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: nullLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getNonServiceLineItems(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getAllLineItems', () => {
|
||||||
|
test('Returns all line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getAllLineItems(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toHaveLength(6);
|
||||||
|
expect(result).toContain(supportingLineItem);
|
||||||
|
expect(result).toContain(glassLineItem);
|
||||||
|
expect(result).toContain(otherLineItem);
|
||||||
|
expect(result).toContain(vapsLineItem);
|
||||||
|
expect(result).toContain(mobileFeeLineItem);
|
||||||
|
expect(result).toContain(recycleFeeLineItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns empty array when line items are null', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: nullLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getAllLineItems(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getRecycleFee', () => {
|
||||||
|
test('Returns recycle fee when present', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getRecycleFeeLineItem(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).not.toBeNull();
|
||||||
|
expect(result).toMatchObject(recycleFeeLineItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns undefined recycle fee when not present', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: emptyLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getRecycleFeeLineItem(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getMobileFee', () => {
|
||||||
|
test('Returns mobile fee when present', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getMobileFeeLineItem(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).not.toBeNull();
|
||||||
|
expect(result).toMatchObject(mobileFeeLineItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns undefined mobile fee when not present', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
lineItems: emptyLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getMobileFeeLineItem(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDeductible', () => {
|
||||||
|
test('Returns deductible on the order', () => {
|
||||||
|
// Arrange
|
||||||
|
const deductible = 100;
|
||||||
|
const order = {
|
||||||
|
currentDeductible: deductible
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getDeductible(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).not.toBeNull();
|
||||||
|
expect(result).toBe(deductible);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isOrderUnverified', () => {
|
||||||
|
test.each([[false, false], [true, true]])('Returns %p when policy.isUnverified is %p', (expected, isUnverified) => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = isOrderUnverified(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isOrderNoComp', () => {
|
||||||
|
test('Returns false when policy is null', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = isOrderNoComp(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([[false, false], [true, true]])('Returns %p when policy.NoCoverage is %p', (expected, noCoverage) => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
policy: {
|
||||||
|
noCoverage
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = isOrderNoComp(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isOrderITAC', () => {
|
||||||
|
test('Returns false when policy is null', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = isOrderITAC(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([[false, false], [true, true]])('Returns %p when policy.isITAC is %p', (expected, isITAC) => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
policy: {
|
||||||
|
isITAC
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = isOrderITAC(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getSubtotal', () => {
|
||||||
|
test('Returns 0 when there are null items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: true
|
||||||
|
},
|
||||||
|
lineItems: nullLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSubtotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns 0 when there are no items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: true
|
||||||
|
},
|
||||||
|
lineItems: emptyLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSubtotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns sub total of deductible + vaps + fee line items when verified deductible', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: false,
|
||||||
|
isITAC: false
|
||||||
|
},
|
||||||
|
currentDeductible: 100,
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSubtotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(310);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns sub total of all line items when verified no comp', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: true,
|
||||||
|
isITAC: false
|
||||||
|
},
|
||||||
|
currentDeductible: 0,
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSubtotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(330);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns sub total of all line items when verified ITAC', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: false,
|
||||||
|
isITAC: true
|
||||||
|
},
|
||||||
|
currentDeductible: 0,
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSubtotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(330);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getSalesTax', () => {
|
||||||
|
test('Returns 0 when there are null items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: true
|
||||||
|
},
|
||||||
|
lineItems: nullLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSalesTax(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns 0 when there are no items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: true
|
||||||
|
},
|
||||||
|
lineItems: emptyLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSalesTax(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns sales tax vaps + fee line items when verified', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: false,
|
||||||
|
isITAC: false
|
||||||
|
},
|
||||||
|
currentDeductible: 100,
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSalesTax(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(15);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns sales tax of all line items when verified no comp', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: true,
|
||||||
|
isITAC: false
|
||||||
|
},
|
||||||
|
currentDeductible: 0,
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSalesTax(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(21);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns sales tax of all line items when verified ITAC', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: false,
|
||||||
|
isITAC: true
|
||||||
|
},
|
||||||
|
currentDeductible: 0,
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getSalesTax(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(21);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getCartTotal', () => {
|
||||||
|
test('Returns 0 when there are null items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: true
|
||||||
|
},
|
||||||
|
lineItems: nullLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getCartTotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns 0 when there are no items', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: true
|
||||||
|
},
|
||||||
|
lineItems: emptyLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getCartTotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns total of vaps + fee line items when verified', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: false,
|
||||||
|
isITAC: false
|
||||||
|
},
|
||||||
|
currentDeductible: 100,
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getCartTotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(325);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns total of all line items when verified no comp', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: true,
|
||||||
|
isITAC: false
|
||||||
|
},
|
||||||
|
currentDeductible: 0,
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getCartTotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(351);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns total of all line items when verified ITAC', () => {
|
||||||
|
// Arrange
|
||||||
|
const order = {
|
||||||
|
isUnverified: false,
|
||||||
|
policy: {
|
||||||
|
noCoverage: false,
|
||||||
|
isITAC: true
|
||||||
|
},
|
||||||
|
currentDeductible: 0,
|
||||||
|
lineItems: defaultLineItems
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getCartTotal(order);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(351);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
4
src/helpers/line-items-helper.js
Normal file
4
src/helpers/line-items-helper.js
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
|
export function getLineItemsFlattened(lineItems) {
|
||||||
|
return lineItems?.flatMap((li) => [li, ...(getLineItemsFlattened(li.childParts))]) ?? [];
|
||||||
|
}
|
||||||
55
src/helpers/line-items-helper.spec.js
Normal file
55
src/helpers/line-items-helper.spec.js
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { getLineItemsFlattened } from '@/helpers/line-items-helper';
|
||||||
|
|
||||||
|
describe('getLineItemsFlattened', () => {
|
||||||
|
describe('getLineItemsFlattened', () => {
|
||||||
|
it('Returns empty array when null is passed', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = null;
|
||||||
|
// Act
|
||||||
|
const result = getLineItemsFlattened(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).not.null;
|
||||||
|
expect(result).toStrictEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Returns empty array when empty array is passed', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [];
|
||||||
|
// Act
|
||||||
|
const result = getLineItemsFlattened(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).not.null;
|
||||||
|
expect(result).toStrictEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Returns line items as flat array without child parts', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [{ partType: 'a' }, { partType: 'b' }, { partType: 'c' }];
|
||||||
|
// Act
|
||||||
|
const result = getLineItemsFlattened(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).not.null;
|
||||||
|
expect(result).toStrictEqual(lineItems);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Returns line items as flat array with child parts', () => {
|
||||||
|
// Arrange
|
||||||
|
const a = { partType: 'a' };
|
||||||
|
const c = { partType: 'c' };
|
||||||
|
const d = { partType: 'd' };
|
||||||
|
const b = { partType: 'b', childParts: [c, d] };
|
||||||
|
const e = { partType: 'e', childParts: null };
|
||||||
|
|
||||||
|
const lineItems = [a, b, e];
|
||||||
|
// Act
|
||||||
|
const result = getLineItemsFlattened(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).not.null;
|
||||||
|
expect(result).toStrictEqual([a, b, c, d, e]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,12 +1,31 @@
|
||||||
function getPriceOfLineItem(lineItem) {
|
/**
|
||||||
return (lineItem?.kitPrice ?? 0)
|
* Returns the price of a single line item. Will include sales tax if includeTax is true
|
||||||
+ (lineItem?.laborAmount ?? 0)
|
* @param {object} lineItem line item to price
|
||||||
+ (lineItem?.sellingPrice ?? 0);
|
* @returns {number} price of the line item
|
||||||
|
*/
|
||||||
|
export function getPriceOfLineItem(lineItem) {
|
||||||
|
let price = (lineItem.kitPrice ?? 0) + (lineItem.laborAmount ?? 0) + (lineItem.sellingPrice ?? 0);
|
||||||
|
if (lineItem.childParts && lineItem.childParts.length !== 0) {
|
||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
price += getPriceOfLineItems(lineItem.childParts);
|
||||||
|
}
|
||||||
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function getPriceOfLineItems(lineItems) {
|
/**
|
||||||
return lineItems.reduce(
|
* Returns the price for the given array of line items. Will include sales tax if includeTax is true
|
||||||
(accumulator, lineItem) => accumulator + getPriceOfLineItem(lineItem),
|
* @param {Array} lineItems array of line items to be priced
|
||||||
0
|
* @returns {number} price of the lines items
|
||||||
);
|
*/
|
||||||
|
export function getPriceOfLineItems(lineItems) {
|
||||||
|
return lineItems?.reduce((accumulator, lineItem) => accumulator + getPriceOfLineItem(lineItem), 0) ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sales tax for the given array of line items
|
||||||
|
* @param {Array} lineItems array of line items to get the sales tax for
|
||||||
|
* @returns {number} sales tax of the line items
|
||||||
|
*/
|
||||||
|
export function getTaxOfLineItems(lineItems) {
|
||||||
|
return lineItems?.reduce((accumulator, lineItem) => accumulator + (lineItem.salesTax ?? 0), 0) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,214 @@
|
||||||
import getPriceOfLineItems from '@/helpers/price-calculator.js';
|
import {
|
||||||
|
getPriceOfLineItem,
|
||||||
|
getPriceOfLineItems,
|
||||||
|
getTaxOfLineItems
|
||||||
|
} from '@/helpers/price-calculator.js';
|
||||||
|
|
||||||
describe('getPriceOfLineItems', () => {
|
describe('price-calculator', () => {
|
||||||
test('Returns zero when no line items', () => {
|
describe('getPriceOfLineItem', () => {
|
||||||
// Arrange
|
test('Empty lineItem returns 0', () => {
|
||||||
const lineItems = [];
|
// Arrange
|
||||||
|
const lineItem = {};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = getPriceOfLineItems(lineItems);
|
const result = getPriceOfLineItem(lineItem);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(result).toBe(0);
|
expect(result).toBe(0);
|
||||||
});
|
});
|
||||||
test('Returns expected when one line item', () => {
|
|
||||||
// Arrange
|
test('Returns kit, labor, sellingPrice total', () => {
|
||||||
const lineItems = [
|
// Arrange
|
||||||
{
|
const lineItem = {
|
||||||
kitPrice: 1,
|
kitPrice: 1,
|
||||||
laborAmount: 2,
|
laborAmount: 2,
|
||||||
sellingPrice: 3
|
sellingPrice: 3,
|
||||||
}
|
salesTax: 4
|
||||||
];
|
};
|
||||||
const expected = 6;
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = getPriceOfLineItems(lineItems);
|
const result = getPriceOfLineItem(lineItem);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(result).toBe(expected);
|
expect(result).toBe(6);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
test('Returns expected when multiple line items', () => {
|
|
||||||
// Arrange
|
|
||||||
const lineItems = [
|
|
||||||
{
|
|
||||||
kitPrice: 1,
|
|
||||||
laborAmount: 2,
|
|
||||||
sellingPrice: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
kitPrice: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
kitPrice: 10,
|
|
||||||
laborAmount: 100,
|
|
||||||
sellingPrice: 1000
|
|
||||||
}
|
|
||||||
];
|
|
||||||
const expected = 1117;
|
|
||||||
|
|
||||||
// Act
|
describe('getPriceOfLineItems', () => {
|
||||||
const result = getPriceOfLineItems(lineItems);
|
test('Returns zero when null', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = null;
|
||||||
|
|
||||||
// Assert
|
// Act
|
||||||
expect(result).toBe(expected);
|
const result = getPriceOfLineItems(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns zero when no line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getPriceOfLineItems(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
test('Returns expected when one line item', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [
|
||||||
|
{
|
||||||
|
kitPrice: 1,
|
||||||
|
laborAmount: 2,
|
||||||
|
sellingPrice: 3
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const expected = 6;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getPriceOfLineItems(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
|
test('Returns expected when multiple line items and child parts', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [
|
||||||
|
{
|
||||||
|
kitPrice: 1,
|
||||||
|
laborAmount: 2,
|
||||||
|
sellingPrice: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kitPrice: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kitPrice: 10,
|
||||||
|
laborAmount: 100,
|
||||||
|
sellingPrice: 1000,
|
||||||
|
childParts: [
|
||||||
|
{
|
||||||
|
kitPrice: 1,
|
||||||
|
laborAmount: 2,
|
||||||
|
sellingPrice: 3,
|
||||||
|
salesTax: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kitPrice: 2,
|
||||||
|
laborAmount: 3,
|
||||||
|
sellingPrice: 4,
|
||||||
|
salesTax: 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const expected = 1132;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getPriceOfLineItems(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getTaxOfLineItems', () => {
|
||||||
|
test('Returns zero when null line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getTaxOfLineItems(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
test('Returns zero when no line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getTaxOfLineItems(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(0);
|
||||||
|
});
|
||||||
|
test('Returns expected when one line item', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [
|
||||||
|
{
|
||||||
|
kitPrice: 1,
|
||||||
|
laborAmount: 2,
|
||||||
|
sellingPrice: 3,
|
||||||
|
salesTax: 4
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const expected = 4;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getTaxOfLineItems(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
|
test('Returns expected when multiple line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [
|
||||||
|
{
|
||||||
|
kitPrice: 1,
|
||||||
|
laborAmount: 2,
|
||||||
|
sellingPrice: 3,
|
||||||
|
salesTax: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kitPrice: 1,
|
||||||
|
salesTax: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kitPrice: 10,
|
||||||
|
laborAmount: 100,
|
||||||
|
sellingPrice: 1000,
|
||||||
|
salesTax: 50
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const expected = 56;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getTaxOfLineItems(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Returns expected when multiple line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [
|
||||||
|
{
|
||||||
|
kitPrice: 1,
|
||||||
|
laborAmount: 2,
|
||||||
|
sellingPrice: 3,
|
||||||
|
salesTax: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kitPrice: 1,
|
||||||
|
salesTax: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kitPrice: 10,
|
||||||
|
laborAmount: 100,
|
||||||
|
sellingPrice: 1000,
|
||||||
|
salesTax: 50
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const expected = 56;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getTaxOfLineItems(lineItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { getLineItemsFlattened } from '@/helpers/line-items-helper';
|
||||||
|
|
||||||
export default function getQueryStringParameter(key) {
|
export default function getQueryStringParameter(key) {
|
||||||
const queryString = window.location.search;
|
const queryString = window.location.search;
|
||||||
const urlParams = new URLSearchParams(queryString);
|
const urlParams = new URLSearchParams(queryString);
|
||||||
|
|
@ -9,3 +11,20 @@ export default function getQueryStringParameter(key) {
|
||||||
|
|
||||||
return lowerCaseParams.get(key.toLowerCase());
|
return lowerCaseParams.get(key.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildQueryStringParameterFromArrayOfComplexObjects(arrayOfObjects, parameterName) {
|
||||||
|
let queryStringParameter = '';
|
||||||
|
for (let i = 0; i < arrayOfObjects.length; i++) {
|
||||||
|
for (const [key, value] of Object.entries(arrayOfObjects[i])) {
|
||||||
|
queryStringParameter += `${parameterName}[${i}].${key}=${value}&`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove trailing &
|
||||||
|
return queryStringParameter.slice(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLineItemQueryString(lineItems, parameterName) {
|
||||||
|
const queryString = getLineItemsFlattened(lineItems).map((lineItem, index) =>
|
||||||
|
`${parameterName}[${index}].partNumber=${lineItem.partNumber}`).join('&');
|
||||||
|
return queryString.length !== 0 ? `&${queryString}` : '';
|
||||||
|
}
|
||||||
|
|
|
||||||
47
src/helpers/querystring-helper.spec.js
Normal file
47
src/helpers/querystring-helper.spec.js
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { buildQueryStringParameterFromArrayOfComplexObjects, getLineItemQueryString } from '@/helpers/querystring-helper';
|
||||||
|
|
||||||
|
describe('querystring-helper', () => {
|
||||||
|
describe('buildQueryStringParameterFromArrayOfComplexObjects', () => {
|
||||||
|
it('returns a query string from a complex object', () => {
|
||||||
|
// Arrange
|
||||||
|
const object = [{ a: 'a', val: 24 }, { a: 'b', val: '52' }];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = buildQueryStringParameterFromArrayOfComplexObjects(object, 'param');
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe('param[0].a=a¶m[0].val=24¶m[1].a=b¶m[1].val=52');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getLineItemQueryString', () => {
|
||||||
|
it('returns empty query string from empty line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const lineItems = [];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getLineItemQueryString(lineItems, 'param');
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result).toBe('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns a query string from line items', () => {
|
||||||
|
// Arrange
|
||||||
|
const a = { partNumber: 'a' };
|
||||||
|
const c = { partNumber: 'c' };
|
||||||
|
const d = { partNumber: 'd' };
|
||||||
|
const b = { partNumber: 'b', childParts: [c, d] };
|
||||||
|
const e = { partNumber: 'e' };
|
||||||
|
|
||||||
|
const lineItems = [a, b, e];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = getLineItemQueryString(lineItems, 'param');
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
expect(result).toBe('¶m[0].partNumber=a¶m[1].partNumber=b¶m[2].partNumber=c¶m[3].partNumber=d¶m[4].partNumber=e');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -5,19 +5,22 @@ import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
|
||||||
// Supporting Files
|
// Supporting Files
|
||||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
import { useMainStore, getDefaultState } from '@/store';
|
import { useMainStore, getDefaultState } from '@/store';
|
||||||
import coverageStatuses from '@/constants/coverage-statuses';
|
|
||||||
import { formatAmountInDollars } from '@/helpers/text-helper.js';
|
import { formatAmountInDollars } from '@/helpers/text-helper.js';
|
||||||
import partTypeStrings from '@/constants/part-type-strings';
|
import partTypeStrings from '@/constants/part-type-strings';
|
||||||
import partNumberStrings from '@/constants/part-number-strings';
|
import partNumberStrings from '@/constants/part-number-strings';
|
||||||
import { getHighestFullySatisfiedTier, getPackageContents } from '@/helpers/service-package-helper.js';
|
import { getHighestFullySatisfiedTier, getPackageContents } from '@/helpers/service-package-helper.js';
|
||||||
import getPriceOfLineItems from '@/helpers/price-calculator.js';
|
import { getPriceOfLineItems } from '@/helpers/price-calculator.js';
|
||||||
|
|
||||||
const VERIFYING_COVERAGE = 'Verifying coverage';
|
const VERIFYING_COVERAGE = 'Verifying coverage';
|
||||||
|
|
||||||
jest.mock('@/helpers/text-helper', () => ({
|
jest.mock('@/helpers/text-helper', () => ({
|
||||||
formatAmountInDollars: jest.fn()
|
formatAmountInDollars: jest.fn()
|
||||||
}));
|
}));
|
||||||
jest.mock('@/helpers/price-calculator.js', () => jest.fn());
|
jest.mock('@/helpers/price-calculator.js', () => ({
|
||||||
|
getPriceOfLineItems: jest.fn(),
|
||||||
|
getTaxOfLineItems: jest.fn(),
|
||||||
|
getPriceOfLineItem: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('@/helpers/service-package-helper', () => ({
|
jest.mock('@/helpers/service-package-helper', () => ({
|
||||||
getHighestFullySatisfiedTier: jest.fn(),
|
getHighestFullySatisfiedTier: jest.fn(),
|
||||||
|
|
@ -201,7 +204,7 @@ describe('cart-dropdown component', () => {
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
supportingItems: [
|
feeItems: [
|
||||||
{ partNumber: partNumberStrings.RECYCLE_FEE }
|
{ partNumber: partNumberStrings.RECYCLE_FEE }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -384,399 +387,6 @@ describe('cart-dropdown component', () => {
|
||||||
// TODO when subTotal and salesTax are finished
|
// TODO when subTotal and salesTax are finished
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('subTotal', () => {
|
|
||||||
const supportingItemPartNumber = 'supporter';
|
|
||||||
const glassPartNumber = 'glass part';
|
|
||||||
const otherPartNumber = 'other';
|
|
||||||
const vapPartNumber = 'vap';
|
|
||||||
const mobileFeePartNumber = 'mobile';
|
|
||||||
const supportingItems = [{ partNumber: supportingItemPartNumber }];
|
|
||||||
const glassParts = [{ partNumber: glassPartNumber }];
|
|
||||||
const otherParts = [{ partNumber: otherPartNumber }];
|
|
||||||
const vaps = [{ partNumber: vapPartNumber }];
|
|
||||||
const mobileFee = { partNumber: mobileFeePartNumber };
|
|
||||||
const includesPartNumber = (lineItems, partNumber) => lineItems.some((item) => item?.partNumber === partNumber);
|
|
||||||
const deductiblePrice = 100;
|
|
||||||
const supportingAndGlassAndOtherPrice = 30;
|
|
||||||
const feesAndVapsPrice = 50;
|
|
||||||
const allLineItemsPrice = 70;
|
|
||||||
getPriceOfLineItems.mockImplementation((lineItems) => {
|
|
||||||
const allPartNumbers = [
|
|
||||||
supportingItemPartNumber,
|
|
||||||
glassPartNumber,
|
|
||||||
otherPartNumber,
|
|
||||||
mobileFeePartNumber,
|
|
||||||
vapPartNumber
|
|
||||||
];
|
|
||||||
if (allPartNumbers.every((partNumber) => includesPartNumber(lineItems, partNumber))) {
|
|
||||||
return allLineItemsPrice;
|
|
||||||
}
|
|
||||||
const supportingAndGlassAndOtherPartNumbers = [
|
|
||||||
supportingItemPartNumber,
|
|
||||||
glassPartNumber,
|
|
||||||
otherPartNumber
|
|
||||||
];
|
|
||||||
if (supportingAndGlassAndOtherPartNumbers.every((partNumber) => includesPartNumber(lineItems, partNumber))) {
|
|
||||||
return supportingAndGlassAndOtherPrice;
|
|
||||||
}
|
|
||||||
if (includesPartNumber(lineItems, mobileFeePartNumber) && includesPartNumber(lineItems, vapPartNumber)) {
|
|
||||||
return feesAndVapsPrice;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
});
|
|
||||||
const lineItems = {
|
|
||||||
supportingItems,
|
|
||||||
glassParts,
|
|
||||||
otherParts,
|
|
||||||
vaps,
|
|
||||||
mobileFee
|
|
||||||
};
|
|
||||||
test('when not no comp and not itac, includes deductible price plus fee and vap price', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
lineItems,
|
|
||||||
policy: {
|
|
||||||
noCoverage: false,
|
|
||||||
isITAC: false
|
|
||||||
},
|
|
||||||
currentDeductible: deductiblePrice
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
const expected = deductiblePrice + feesAndVapsPrice;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.subTotal;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(expected);
|
|
||||||
});
|
|
||||||
test('when no comp, returns all line items price', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
lineItems,
|
|
||||||
policy: {
|
|
||||||
noCoverage: true,
|
|
||||||
isITAC: false
|
|
||||||
},
|
|
||||||
currentDeductible: deductiblePrice
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
const expected = allLineItemsPrice;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.subTotal;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(expected);
|
|
||||||
});
|
|
||||||
test('when ITAC, returns all line items price', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
lineItems,
|
|
||||||
policy: {
|
|
||||||
noCoverage: false,
|
|
||||||
isITAC: true
|
|
||||||
},
|
|
||||||
currentDeductible: deductiblePrice
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
const expected = allLineItemsPrice;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.subTotal;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('salesTax', () => {
|
|
||||||
test('salesTax is treated as 0 when line items are null', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
policy: {
|
|
||||||
policyLookupSuccessful: true
|
|
||||||
},
|
|
||||||
currentDeductible: 250,
|
|
||||||
lineItems: {
|
|
||||||
glassParts: null,
|
|
||||||
otherParts: null,
|
|
||||||
supportingItems: null,
|
|
||||||
vaps: null
|
|
||||||
},
|
|
||||||
payment: {
|
|
||||||
insuranceCoverage: { isVerified: true }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
issConfig: {
|
|
||||||
isClaimRegistrationRequired: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.salesTax;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("salesTax is treated as 0 when null or undefined is set as the line item's sales tax.", () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
policy: {
|
|
||||||
policyLookupSuccessful: true
|
|
||||||
},
|
|
||||||
currentDeductible: 250,
|
|
||||||
lineItems: {
|
|
||||||
glassParts: [
|
|
||||||
{ partType: 'mock', salesTax: null },
|
|
||||||
{ partType: 'mock', salesTax: undefined }
|
|
||||||
],
|
|
||||||
supportingItems: [
|
|
||||||
{ partType: 'mock', salesTax: null },
|
|
||||||
{ partType: 'mock', salesTax: undefined }
|
|
||||||
],
|
|
||||||
vaps: [
|
|
||||||
{ partType: 'mock', salesTax: null },
|
|
||||||
{ partType: 'mock', salesTax: undefined }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
payment: {
|
|
||||||
insuranceCoverage: { isVerified: true }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
issConfig: {
|
|
||||||
isClaimRegistrationRequired: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.salesTax;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(0);
|
|
||||||
});
|
|
||||||
test('Returns 0 as sales tax when coverage is unverified and order does not contain vaps.', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
policy: {
|
|
||||||
policyLookupSuccessful: true
|
|
||||||
},
|
|
||||||
currentDeductible: 250,
|
|
||||||
lineItems: {
|
|
||||||
glassParts: [{ partType: 'mock', salesTax: 10 }],
|
|
||||||
supportingItems: [
|
|
||||||
{
|
|
||||||
partNumber: partNumberStrings.RECYCLE_FEE,
|
|
||||||
partType: 'mock',
|
|
||||||
salesTax: 10,
|
|
||||||
sellingPrice: 39.99
|
|
||||||
}
|
|
||||||
],
|
|
||||||
vaps: []
|
|
||||||
},
|
|
||||||
payment: {
|
|
||||||
insuranceCoverage: { isVerified: false }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
issConfig: {
|
|
||||||
isClaimRegistrationRequired: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.salesTax;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Returns sum of vaps sales tax when coverage is unverified and order has vaps.', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
policy: {
|
|
||||||
policyLookupSuccessful: true
|
|
||||||
},
|
|
||||||
currentDeductible: 250,
|
|
||||||
lineItems: {
|
|
||||||
glassParts: [{ partType: 'mock', salesTax: 10 }],
|
|
||||||
vaps: [
|
|
||||||
{ partType: 'mock', salesTax: 1 },
|
|
||||||
{ partType: 'mock', salesTax: 2 }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
payment: {
|
|
||||||
insuranceCoverage: { isVerified: false }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
issConfig: {
|
|
||||||
isClaimRegistrationRequired: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.salesTax;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Returns Recycle Fee tax when coverage is Verified-Deductible, replace service, and no vaps.', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
policy: {
|
|
||||||
policyLookupSuccessful: true,
|
|
||||||
noCoverage: false,
|
|
||||||
isITAC: false
|
|
||||||
},
|
|
||||||
currentDeductible: 250,
|
|
||||||
lineItems: {
|
|
||||||
glassParts: [{ partType: 'mock', salesTax: 10, sellingPrice: 150 }],
|
|
||||||
supportingItems: [
|
|
||||||
{
|
|
||||||
partNumber: partNumberStrings.RECYCLE_FEE,
|
|
||||||
partType: 'mock',
|
|
||||||
salesTax: 10,
|
|
||||||
sellingPrice: 39.99
|
|
||||||
}
|
|
||||||
],
|
|
||||||
vaps: null
|
|
||||||
},
|
|
||||||
payment: {
|
|
||||||
insuranceCoverage: { isVerified: true }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
issConfig: {
|
|
||||||
isClaimRegistrationRequired: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.salesTax;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(10);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Returns sum of vaps + recycle fee sales tax when Verified-Deductible, replace service, and has vaps.', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
policy: {
|
|
||||||
policyLookupSuccessful: true
|
|
||||||
},
|
|
||||||
currentDeductible: 250,
|
|
||||||
lineItems: {
|
|
||||||
glassParts: [{ partType: 'mock', salesTax: 10, sellingPrice: 100 }],
|
|
||||||
otherParts: [{ partType: 'mock', salesTax: 10, kitPrice: 100 }],
|
|
||||||
supportingItems: [
|
|
||||||
{ partNumber: partNumberStrings.RECYCLE_FEE, partType: 'mock', salesTax: 10, sellingPrice: 39.99 },
|
|
||||||
{ partType: 'mock', salesTax: 10, kitPrice: 100 }
|
|
||||||
],
|
|
||||||
vaps: [
|
|
||||||
{ partType: 'mock', salesTax: 2 },
|
|
||||||
{ partType: 'mock', salesTax: 3 }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
payment: {
|
|
||||||
insuranceCoverage: { isVerified: true }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
issConfig: {
|
|
||||||
isClaimRegistrationRequired: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.salesTax;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(15);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Returns sum of sales tax when Verified-ITAC.', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
currentDeductible: 0,
|
|
||||||
lineItems: {
|
|
||||||
glassParts: [{ partType: 'mock', salesTax: 10, sellingPrice: 100 }],
|
|
||||||
otherParts: [{ partType: 'mock', salesTax: 10, kitPrice: 100 }],
|
|
||||||
supportingItems: [{ partType: 'mock', salesTax: 10, kitPrice: 100 }],
|
|
||||||
vaps: [{ partType: 'mock', salesTax: 5 }]
|
|
||||||
},
|
|
||||||
payment: {
|
|
||||||
insuranceCoverage: { isVerified: true }
|
|
||||||
},
|
|
||||||
policy: {
|
|
||||||
isITAC: true,
|
|
||||||
policyLookupSuccessful: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
issConfig: {
|
|
||||||
isClaimRegistrationRequired: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.salesTax;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(35);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Returns sum of sales tax when Verified-NoComp.', () => {
|
|
||||||
// Arrange
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
currentDeductible: 0,
|
|
||||||
lineItems: {
|
|
||||||
glassParts: [{ partType: 'mock', salesTax: 10, sellingPrice: 100 }],
|
|
||||||
otherParts: [{ partType: 'mock', salesTax: 10, kitPrice: 100 }],
|
|
||||||
supportingItems: [{ partType: 'mock', salesTax: 10, kitPrice: 100 }],
|
|
||||||
vaps: [{ partType: 'mock', salesTax: 5 }]
|
|
||||||
},
|
|
||||||
payment: {
|
|
||||||
insuranceCoverage: { isVerified: true }
|
|
||||||
},
|
|
||||||
policy: {
|
|
||||||
noCoverage: true,
|
|
||||||
policyLookupSuccessful: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
issConfig: {
|
|
||||||
isClaimRegistrationRequired: true,
|
|
||||||
enableNoCompQuote: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.salesTax;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(35);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('availableLineItems', () => {
|
describe('availableLineItems', () => {
|
||||||
test('returns expected when all null', () => {
|
test('returns expected when all null', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -848,7 +458,9 @@ describe('cart-dropdown component', () => {
|
||||||
const mobileFee = { partNumber: 'mobile' };
|
const mobileFee = { partNumber: 'mobile' };
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: { mobileFee }
|
lineItems: {
|
||||||
|
feeItems: [mobileFee]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const propsData = { availableVaps: null };
|
const propsData = { availableVaps: null };
|
||||||
|
|
@ -888,7 +500,7 @@ describe('cart-dropdown component', () => {
|
||||||
glassParts: [part1],
|
glassParts: [part1],
|
||||||
supportingItems: [part2, part3],
|
supportingItems: [part2, part3],
|
||||||
otherParts: [],
|
otherParts: [],
|
||||||
mobileFee
|
feeItems: [mobileFee]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1147,7 +759,7 @@ describe('cart-dropdown component', () => {
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
supportingItems: [
|
feeItems: [
|
||||||
{
|
{
|
||||||
partNumber: partNumberStrings.RECYCLE_FEE
|
partNumber: partNumberStrings.RECYCLE_FEE
|
||||||
}
|
}
|
||||||
|
|
@ -1170,9 +782,7 @@ describe('cart-dropdown component', () => {
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
mobileFee: {
|
feeItems: [{ partType: partTypeStrings.MOBILE_FEE }]
|
||||||
partType: partTypeStrings.MOBILE_FEE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1368,14 +978,10 @@ describe('cart-dropdown component', () => {
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
supportingItems: [
|
feeItems: [
|
||||||
{
|
{ partType: partTypeStrings.MOBILE_FEE },
|
||||||
partNumber: partNumberStrings.RECYCLE_FEE
|
{ partNumber: partNumberStrings.RECYCLE_FEE }
|
||||||
}
|
|
||||||
],
|
],
|
||||||
mobileFee: {
|
|
||||||
partType: partTypeStrings.MOBILE_FEE
|
|
||||||
},
|
|
||||||
vaps: [
|
vaps: [
|
||||||
{ partType: partTypeStrings.RECALIBRATION },
|
{ partType: partTypeStrings.RECALIBRATION },
|
||||||
{ partType: partTypeStrings.FRONT_WIPER },
|
{ partType: partTypeStrings.FRONT_WIPER },
|
||||||
|
|
@ -1533,7 +1139,7 @@ describe('cart-dropdown component', () => {
|
||||||
// Assert
|
// Assert
|
||||||
expect(result).toStrictEqual(expected);
|
expect(result).toStrictEqual(expected);
|
||||||
});
|
});
|
||||||
test('returns expected when recycle fee in supporting items', () => {
|
test('returns expected when recycle fee in fee items', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const mountOptions = getMountOptions({
|
const mountOptions = getMountOptions({
|
||||||
router: { navigate: jest.fn() }
|
router: { navigate: jest.fn() }
|
||||||
|
|
@ -1549,7 +1155,7 @@ describe('cart-dropdown component', () => {
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
supportingItems: [{ partNumber: partNumberStrings.RECYCLE_FEE }]
|
feeItems: [{ partNumber: partNumberStrings.RECYCLE_FEE }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1587,7 +1193,7 @@ describe('cart-dropdown component', () => {
|
||||||
// Assert
|
// Assert
|
||||||
expect(result).toStrictEqual(expected);
|
expect(result).toStrictEqual(expected);
|
||||||
});
|
});
|
||||||
test('returns expected when mobile fee in supporting items', () => {
|
test('returns expected when mobile fee in fee items', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const mountOptions = getMountOptions({
|
const mountOptions = getMountOptions({
|
||||||
router: { navigate: jest.fn() }
|
router: { navigate: jest.fn() }
|
||||||
|
|
@ -1603,7 +1209,7 @@ describe('cart-dropdown component', () => {
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
lineItems: {
|
lineItems: {
|
||||||
mobileFee: { partType: partTypeStrings.MOBILE_FEE }
|
feeItems: [{ partType: partTypeStrings.MOBILE_FEE }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
id="cart-base-price"
|
id="cart-base-price"
|
||||||
class="d-flex justify-content-between align-items-center">
|
class="d-flex justify-content-between align-items-center">
|
||||||
<span id="base-price-label">{{ basePriceLabel }}</span>
|
<span id="base-price-label">{{ basePriceLabel }}</span>
|
||||||
<span id="base-price-value">{{ getDisplayed(baseServicePrice) }}</span>
|
<span id="base-price-value">{{ getDisplayed(servicePrice) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -159,15 +159,22 @@ import { useMainStore } from '@/store';
|
||||||
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
|
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
|
||||||
import textBlock from '@/digital-components/text-block/text-block.vue';
|
import textBlock from '@/digital-components/text-block/text-block.vue';
|
||||||
import textLink from '@/ux-components/text-link/text-link.vue';
|
import textLink from '@/ux-components/text-link/text-link.vue';
|
||||||
import getPriceOfLineItems from '@/helpers/price-calculator.js';
|
|
||||||
import { formatAmountInDollars } from '@/helpers/text-helper.js';
|
import { formatAmountInDollars } from '@/helpers/text-helper.js';
|
||||||
import { getHighestFullySatisfiedTier, getPackageContents } from '@/helpers/service-package-helper.js';
|
import { getHighestFullySatisfiedTier, getPackageContents } from '@/helpers/service-package-helper.js';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import partTypeStrings from '@/constants/part-type-strings.js';
|
import partTypeStrings from '@/constants/part-type-strings.js';
|
||||||
import cartItemType from '@/constants/cart-item-type.js';
|
import cartItemType from '@/constants/cart-item-type.js';
|
||||||
import partNumberStrings from '@/constants/part-number-strings.js';
|
|
||||||
import widgetFields from '@/constants/cms-widget-fields.js';
|
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||||
|
import {
|
||||||
|
getCartTotal,
|
||||||
|
getDeductible,
|
||||||
|
getLineItems, getMobileFeeLineItem,
|
||||||
|
getRecycleFeeLineItem, getSalesTax,
|
||||||
|
getServiceLineItems, getSubtotal, isOrderITAC, isOrderNoComp,
|
||||||
|
isOrderUnverified
|
||||||
|
} from '@/helpers/cart-helper';
|
||||||
|
import { getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator';
|
||||||
|
|
||||||
const VERIFYING_COVERAGE = 'Verifying coverage';
|
const VERIFYING_COVERAGE = 'Verifying coverage';
|
||||||
|
|
||||||
|
|
@ -206,106 +213,58 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
cartOrder() {
|
||||||
|
return this.submittedOrder ?? useMainStore().order;
|
||||||
|
},
|
||||||
deductible() {
|
deductible() {
|
||||||
// Note: added as computed so it can be used in the template.
|
return getDeductible(this.cartOrder);
|
||||||
return this.submittedOrder ? this.submittedOrder.currentDeductible : useMainStore().order.currentDeductible;
|
|
||||||
},
|
},
|
||||||
showDeductibleCartItem() {
|
showDeductibleCartItem() {
|
||||||
const { isUnverified } = useMainStore();
|
return this.isUnverified || (!this.isNoComp && !this.isITAC);
|
||||||
return isUnverified || (!this.isNoComp && !this.isITAC);
|
|
||||||
},
|
},
|
||||||
lineItems() {
|
lineItems() {
|
||||||
return this.submittedOrder ? this.submittedOrder.lineItems : useMainStore().lineItems;
|
return getLineItems(this.cartOrder);
|
||||||
},
|
},
|
||||||
recycleFeeLineItem() {
|
recycleFeeLineItem() {
|
||||||
return this.lineItems.supportingItems
|
return getRecycleFeeLineItem(this.cartOrder);
|
||||||
?.find((lineItem) => lineItem.partNumber === partNumberStrings.RECYCLE_FEE);
|
|
||||||
},
|
},
|
||||||
baseServiceLineItems() {
|
servicePrice() {
|
||||||
const { supportingItems, glassParts, otherParts } = this.lineItems;
|
return getPriceOfLineItems(getServiceLineItems(this.cartOrder)) ?? 0;
|
||||||
const parts = [
|
|
||||||
...(supportingItems ?? []),
|
|
||||||
...(glassParts ?? []),
|
|
||||||
...(otherParts ?? [])
|
|
||||||
];
|
|
||||||
return parts.filter((part) => part !== this.recycleFeeLineItem);
|
|
||||||
},
|
},
|
||||||
baseServicePrice() {
|
isUnverified() {
|
||||||
return getPriceOfLineItems(this.baseServiceLineItems) ?? 0;
|
return isOrderUnverified(this.cartOrder);
|
||||||
},
|
},
|
||||||
isITAC() {
|
isITAC() {
|
||||||
return this.submittedOrder ? this.submittedOrder.policy.isITAC : useMainStore().isITAC;
|
return isOrderITAC(this.cartOrder);
|
||||||
},
|
},
|
||||||
isNoComp() {
|
isNoComp() {
|
||||||
return this.submittedOrder ? this.submittedOrder.policy.noCoverage : useMainStore().isNoComp;
|
return isOrderNoComp(this.cartOrder);
|
||||||
},
|
},
|
||||||
// TODO fix rounding
|
// TODO fix rounding
|
||||||
subTotal() {
|
subTotal() {
|
||||||
const { supportingItems, glassParts, otherParts, vaps, mobileFee } = this.lineItems;
|
return getSubtotal(this.cartOrder);
|
||||||
const allLineItems = [
|
|
||||||
...(supportingItems ?? []),
|
|
||||||
...(glassParts ?? []),
|
|
||||||
...(otherParts ?? []),
|
|
||||||
...(vaps ?? []),
|
|
||||||
mobileFee
|
|
||||||
];
|
|
||||||
return !this.isNoComp && !this.isITAC
|
|
||||||
? this.deductible + getPriceOfLineItems([...this.feeLineItems, ...(vaps ?? [])])
|
|
||||||
: getPriceOfLineItems(allLineItems);
|
|
||||||
},
|
|
||||||
feeLineItems() {
|
|
||||||
const { mobileFee } = this.lineItems;
|
|
||||||
const result = [];
|
|
||||||
if (mobileFee) {
|
|
||||||
result.push(mobileFee);
|
|
||||||
}
|
|
||||||
if (this.recycleFeeLineItem) {
|
|
||||||
result.push(this.recycleFeeLineItem);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
},
|
||||||
salesTax() {
|
salesTax() {
|
||||||
const { isUnverified } = useMainStore();
|
return getSalesTax(this.cartOrder);
|
||||||
function sumTax(lineItems) {
|
},
|
||||||
return lineItems?.reduce((accumulator, lineItem) => accumulator + (lineItem.salesTax ?? 0), 0) ?? 0;
|
total() {
|
||||||
}
|
return getCartTotal(this.cartOrder);
|
||||||
|
|
||||||
let result = 0;
|
|
||||||
|
|
||||||
if (!isUnverified) {
|
|
||||||
if (this.isITAC || this.isNoComp) {
|
|
||||||
result += sumTax(this.baseServiceLineItems);
|
|
||||||
} else {
|
|
||||||
// deductible-case need to show tax for Recycle Fee
|
|
||||||
result += this.recycleFeeLineItem?.salesTax ?? 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result += sumTax(this.lineItems.vaps ?? []);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
},
|
||||||
amountDue() {
|
amountDue() {
|
||||||
return this.showAsPaid
|
return this.showAsPaid ? 0 : this.total;
|
||||||
? 0
|
|
||||||
: this.subTotal + this.salesTax;
|
|
||||||
},
|
},
|
||||||
amountPaid() {
|
amountPaid() {
|
||||||
return !this.showAsPaid
|
return !this.showAsPaid ? 0 : this.total;
|
||||||
? 0
|
|
||||||
: this.subTotal + this.salesTax;
|
|
||||||
},
|
},
|
||||||
availableLineItems() {
|
availableLineItems() {
|
||||||
const { supportingItems, glassParts, otherParts, mobileFee } = this.lineItems;
|
const { supportingItems, glassParts, otherParts, feeItems } = this.lineItems;
|
||||||
const result = [
|
const result = [
|
||||||
...(supportingItems ?? []),
|
...(supportingItems ?? []),
|
||||||
...(glassParts ?? []),
|
...(glassParts ?? []),
|
||||||
...(otherParts ?? []),
|
...(otherParts ?? []),
|
||||||
...(this.availableVaps ?? [])
|
...(this.availableVaps ?? []),
|
||||||
|
...(feeItems ?? [])
|
||||||
];
|
];
|
||||||
if (mobileFee) {
|
|
||||||
result.push(mobileFee);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
vehicleDamage() {
|
vehicleDamage() {
|
||||||
|
|
@ -378,6 +337,12 @@ export default {
|
||||||
rainDefenseCartItem() {
|
rainDefenseCartItem() {
|
||||||
return this.getCartItemForVapsPart(partTypeStrings.RAIN_DEFENSE);
|
return this.getCartItemForVapsPart(partTypeStrings.RAIN_DEFENSE);
|
||||||
},
|
},
|
||||||
|
allCartItems() {
|
||||||
|
return [
|
||||||
|
...this.servicePackageCartItems,
|
||||||
|
...this.nonServicePackageCartItems
|
||||||
|
];
|
||||||
|
},
|
||||||
packagePrice() {
|
packagePrice() {
|
||||||
return this.servicePackageCartItems?.reduce(
|
return this.servicePackageCartItems?.reduce(
|
||||||
(accumulator, cartItem) => accumulator + (cartItem?.subTotal ?? 0),
|
(accumulator, cartItem) => accumulator + (cartItem?.subTotal ?? 0),
|
||||||
|
|
@ -428,7 +393,7 @@ export default {
|
||||||
: null;
|
: null;
|
||||||
},
|
},
|
||||||
mobileFeeCartItem() {
|
mobileFeeCartItem() {
|
||||||
const mobileFeeLineItem = this.lineItems.mobileFee;
|
const mobileFeeLineItem = getMobileFeeLineItem(this.cartOrder);
|
||||||
return mobileFeeLineItem
|
return mobileFeeLineItem
|
||||||
? this.getCartItem(
|
? this.getCartItem(
|
||||||
this.getCmsContent(this.widget.mobileFee, widgetFields.TEXT_BLOCK_WIDGET.TEXT),
|
this.getCmsContent(this.widget.mobileFee, widgetFields.TEXT_BLOCK_WIDGET.TEXT),
|
||||||
|
|
@ -437,23 +402,6 @@ export default {
|
||||||
partTypeStrings.MOBILE_FEE
|
partTypeStrings.MOBILE_FEE
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
},
|
|
||||||
isUnverified() {
|
|
||||||
const { isClaimRegistrationRequired } = useMainStore().issConfig;
|
|
||||||
const registerClaimSuccessful = !!this.submittedOrder.payment.insuranceCoverage.isVerified;
|
|
||||||
if (!this.submittedOrder.policy.policyLookupSuccessful) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.isNoComp && !useMainStore().issConfig.enableNoCompQuote) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!this.isNoComp && this.deductible == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (isClaimRegistrationRequired && !registerClaimSuccessful) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -464,8 +412,7 @@ export default {
|
||||||
this.isExpanded = !this.isExpanded;
|
this.isExpanded = !this.isExpanded;
|
||||||
},
|
},
|
||||||
getDisplayed(amount) {
|
getDisplayed(amount) {
|
||||||
const isUnverified = this.submittedOrder ? this.isUnverified : useMainStore().isUnverified;
|
return this.isUnverified
|
||||||
return isUnverified
|
|
||||||
? VERIFYING_COVERAGE
|
? VERIFYING_COVERAGE
|
||||||
: formatAmountInDollars(amount);
|
: formatAmountInDollars(amount);
|
||||||
},
|
},
|
||||||
|
|
@ -478,10 +425,7 @@ export default {
|
||||||
cartItemType: cartItemTypeString,
|
cartItemType: cartItemTypeString,
|
||||||
partType,
|
partType,
|
||||||
subTotal: getPriceOfLineItems(lineItems),
|
subTotal: getPriceOfLineItems(lineItems),
|
||||||
salesTax: lineItems?.reduce(
|
salesTax: getTaxOfLineItems(lineItems)
|
||||||
(accumulator, lineItem) => accumulator + lineItem.salesTax,
|
|
||||||
0
|
|
||||||
) ?? 0
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,12 @@ import { getRandomString, getRandomInt } from '@/helpers/data-generation.js';
|
||||||
import settleAllPromises from '@/helpers/layout-helper.js';
|
import settleAllPromises from '@/helpers/layout-helper.js';
|
||||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||||
import { useMainStore, getDefaultState } from '@/store';
|
import { useMainStore, getDefaultState } from '@/store';
|
||||||
import getPriceOfLineItems from '@/helpers/price-calculator.js';
|
import { getPriceOfLineItems } from '@/helpers/price-calculator.js';
|
||||||
|
|
||||||
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
|
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
|
||||||
jest.mock('@/helpers/price-calculator.js', () => jest.fn());
|
jest.mock('@/helpers/price-calculator.js', () => ({
|
||||||
|
getPriceOfLineItems: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('@/helpers/cms-content-helper', () => ({
|
jest.mock('@/helpers/cms-content-helper', () => ({
|
||||||
fetchCmsContentForPage: jest.fn(),
|
fetchCmsContentForPage: jest.fn(),
|
||||||
|
|
|
||||||
|
|
@ -123,9 +123,9 @@ import issPageValues from '@/router/router-constants/issPage-values';
|
||||||
import bailoutMessage from '@/constants/bailoutMessage';
|
import bailoutMessage from '@/constants/bailoutMessage';
|
||||||
import coverageStatuses from '@/constants/coverage-statuses';
|
import coverageStatuses from '@/constants/coverage-statuses';
|
||||||
import widgetFields from '@/constants/cms-widget-fields.js';
|
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||||
import getPriceOfLineItems from '@/helpers/price-calculator.js';
|
|
||||||
import { formatAmountInDollars } from '@/helpers/text-helper.js';
|
import { formatAmountInDollars } from '@/helpers/text-helper.js';
|
||||||
import showIssLoadingModal from '@/helpers/loading-modal-helper';
|
import showIssLoadingModal from '@/helpers/loading-modal-helper';
|
||||||
|
import { getPriceOfLineItems } from '@/helpers/price-calculator';
|
||||||
|
|
||||||
const SAFELITE_PROVIDER = 'Safelite';
|
const SAFELITE_PROVIDER = 'Safelite';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ import { useMainStore } from '@/store';
|
||||||
import { paymentMethods, hopPaymentMethods } from '@/constants/payment-method-constants.js';
|
import { paymentMethods, hopPaymentMethods } from '@/constants/payment-method-constants.js';
|
||||||
import queryStrings from '@/constants/query-strings';
|
import queryStrings from '@/constants/query-strings';
|
||||||
import CartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
|
import CartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
|
||||||
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
|
import settleAllPromises from '@/helpers/layout-helper';
|
||||||
|
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||||
|
import baseMixin from '@/mixins/base-mixin';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const parts = {
|
const parts = {
|
||||||
|
|
@ -105,130 +109,124 @@ const taxedParts = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup global mocks
|
// Setup global mocks
|
||||||
let mockCmsContent = {};
|
// Mock fetchCmsContentForPage
|
||||||
|
|
||||||
jest.mock('@/mixins/base-mixin.js', () => ({
|
|
||||||
methods: {
|
|
||||||
getAmountDue: jest.fn().mockImplementation(() => 5),
|
|
||||||
getDisplayAmountDue: jest.fn().mockImplementation(() => '$5.00')
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('@/helpers/cms-content-helper', () => ({
|
jest.mock('@/helpers/cms-content-helper', () => ({
|
||||||
fetchCmsContentForPage: () => Promise.resolve('content')
|
fetchCmsContentForPage: jest.fn(),
|
||||||
|
doesCopyContainRouterLink: jest.fn()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function setupMocks({ customMountOptions = {}, queryString }) {
|
// Mock our module for promises.
|
||||||
|
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
|
||||||
|
|
||||||
|
function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRunAfterInitializingStore = () => {}, queryString = {}) {
|
||||||
const mountOptions = getMountOptions({
|
const mountOptions = getMountOptions({
|
||||||
...customMountOptions,
|
router: {
|
||||||
|
navigate: jest.fn()
|
||||||
|
},
|
||||||
route: { query: { issPage: 'page-name', ...queryString }, params: {} }
|
route: { query: { issPage: 'page-name', ...queryString }, params: {} }
|
||||||
});
|
});
|
||||||
|
|
||||||
// set all mock stuff
|
const testingPinia = createTestingPinia({
|
||||||
mountOptions.mixins = [
|
initialState: {
|
||||||
{
|
main: mainInitialState
|
||||||
methods: {
|
|
||||||
getCmsContent: jest.fn().mockImplementation((widgetName, fieldName) => {
|
|
||||||
if (mockCmsContent[widgetName] && mockCmsContent[widgetName][fieldName]) {
|
|
||||||
return mockCmsContent[widgetName][fieldName];
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}),
|
|
||||||
setCmsContent: jest.fn()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
];
|
});
|
||||||
|
useMainStore(testingPinia);
|
||||||
|
methodToRunAfterInitializingStore();
|
||||||
|
|
||||||
|
mountOptions.global.plugins = [testingPinia];
|
||||||
|
mountOptions.data = () => (initialData);
|
||||||
|
|
||||||
|
const apiResponses = { cmsContent: {} };
|
||||||
|
|
||||||
|
settleAllPromises.mockImplementation(() => apiResponses);
|
||||||
|
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
|
||||||
|
|
||||||
const wrapper = shallowMount(payment, mountOptions);
|
const wrapper = shallowMount(payment, mountOptions);
|
||||||
|
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {});
|
||||||
|
wrapper.vm.setCmsContent = jest.fn();
|
||||||
|
wrapper.vm.$router.navigateWithSpinner = jest.fn();
|
||||||
|
wrapper.vm.navigateBack = baseMixin.methods.navigateBack;
|
||||||
|
|
||||||
// act on vm
|
return { wrapper };
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('payment-page.vue', () => {
|
const defaultOrder = {
|
||||||
beforeEach(() => {
|
order: {
|
||||||
useMainStore().order =
|
vehicle: {
|
||||||
{
|
year: '2020',
|
||||||
vehicle: {
|
make: 'acura',
|
||||||
year: '2020',
|
model: 'mdx',
|
||||||
make: 'acura',
|
style: '4-door sedan',
|
||||||
model: 'mdx',
|
carId: 'dummyCarId',
|
||||||
style: '4-door sedan',
|
category: 'dummyCategory',
|
||||||
carId: 'dummyCarId',
|
vin: 'dummyVin'
|
||||||
category: 'dummyCategory',
|
},
|
||||||
vin: 'dummyVin'
|
serviceLocation: {
|
||||||
},
|
address: 'add1',
|
||||||
serviceLocation: {
|
address2: 'add2',
|
||||||
address: 'add1',
|
city: 'city',
|
||||||
address2: 'add2',
|
state: 'state',
|
||||||
city: 'city',
|
zipCode: 'zip',
|
||||||
state: 'state',
|
zipCodeCtu: 'zipCtu',
|
||||||
zipCode: 'zip',
|
appointmentType: 'IN_SHOP',
|
||||||
zipCodeCtu: 'zipCtu',
|
isVehicleProtected: true,
|
||||||
appointmentType: 'IN_SHOP',
|
provider: {
|
||||||
isVehicleProtected: true,
|
providerNumber: 2,
|
||||||
provider: {
|
address: {
|
||||||
providerNumber: 2,
|
streetAddress: 'add3',
|
||||||
address: {
|
city: 'city2',
|
||||||
streetAddress: 'add3',
|
state: 'state2',
|
||||||
city: 'city2',
|
zipCode: 'zip2',
|
||||||
state: 'state2',
|
zipCodeCtu: 'zipCtu2'
|
||||||
zipCode: 'zip2',
|
|
||||||
zipCodeCtu: 'zipCtu2'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
techNotes: ''
|
|
||||||
},
|
|
||||||
contactInfo: {
|
|
||||||
firstName: 'first',
|
|
||||||
lastName: 'last',
|
|
||||||
emailAddress: 'builddigitaltest@safelite.com',
|
|
||||||
servicePhone: '555-555-5555'
|
|
||||||
},
|
|
||||||
damage: {
|
|
||||||
isRepair: false,
|
|
||||||
numberOfChips: null,
|
|
||||||
glassToReplace: [{ location: 'windshield' }]
|
|
||||||
},
|
|
||||||
lineItems: {
|
|
||||||
glassParts: [parts.windshield],
|
|
||||||
supportingItems: [],
|
|
||||||
vaps: [parts.frontWipers],
|
|
||||||
promos: []
|
|
||||||
},
|
|
||||||
payment: {
|
|
||||||
isInsurance: false,
|
|
||||||
insuranceCoverage: {
|
|
||||||
isVerified: null,
|
|
||||||
coverageStatus: null,
|
|
||||||
coverageVerificationType: null
|
|
||||||
},
|
|
||||||
isPayInAdvance: true,
|
|
||||||
payInAdvanceType: 'Afterpay',
|
|
||||||
inactivePromos: []
|
|
||||||
},
|
|
||||||
schedule: {
|
|
||||||
date: 'date',
|
|
||||||
startTime: 'start',
|
|
||||||
endTime: 'end',
|
|
||||||
jobMinMinutes: '30',
|
|
||||||
jobMaxMinutes: '45'
|
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
techNotes: ''
|
||||||
mockCmsContent = {};
|
},
|
||||||
});
|
contactInfo: {
|
||||||
|
firstName: 'first',
|
||||||
afterEach(() => {
|
lastName: 'last',
|
||||||
jest.clearAllMocks();
|
emailAddress: 'builddigitaltest@safelite.com',
|
||||||
});
|
servicePhone: '555-555-5555'
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [{location: 'windshield'}]
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: [parts.windshield],
|
||||||
|
supportingItems: [],
|
||||||
|
vaps: [parts.frontWipers],
|
||||||
|
promos: []
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
isInsurance: false,
|
||||||
|
insuranceCoverage: {
|
||||||
|
isVerified: null,
|
||||||
|
coverageStatus: null,
|
||||||
|
coverageVerificationType: null
|
||||||
|
},
|
||||||
|
isPayInAdvance: true,
|
||||||
|
payInAdvanceType: 'Afterpay',
|
||||||
|
inactivePromos: []
|
||||||
|
},
|
||||||
|
schedule: {
|
||||||
|
date: 'date',
|
||||||
|
startTime: 'start',
|
||||||
|
endTime: 'end',
|
||||||
|
jobMinMinutes: '30',
|
||||||
|
jobMaxMinutes: '45'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('payment-page.vue', () => {
|
||||||
describe('arePagePrerequisitesValid', () => {
|
describe('arePagePrerequisitesValid', () => {
|
||||||
test('Returns true in nominal conditions', () => {
|
test('Returns true in nominal conditions', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
// Store defaults are valid
|
// Store defaults are valid
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
@ -240,9 +238,9 @@ describe('payment-page.vue', () => {
|
||||||
describe('Payment method cases', () => {
|
describe('Payment method cases', () => {
|
||||||
test('Returns false if pia options are not valid', () => {
|
test('Returns false if pia options are not valid', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
useMainStore().order.payment.isPayInAdvance = null;
|
useMainStore().order.payment.isPayInAdvance = null;
|
||||||
useMainStore().order.payment.payInAdvanceType = null;
|
useMainStore().order.payment.payInAdvanceType = null;
|
||||||
const wrapper = setupMocks({});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
@ -253,9 +251,9 @@ describe('payment-page.vue', () => {
|
||||||
|
|
||||||
test('Returns false if pay at time of service', () => {
|
test('Returns false if pay at time of service', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
useMainStore().order.payment.isPayInAdvance = false;
|
useMainStore().order.payment.isPayInAdvance = false;
|
||||||
useMainStore().order.payment.payInAdvanceType = null;
|
useMainStore().order.payment.payInAdvanceType = null;
|
||||||
const wrapper = setupMocks({});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
@ -270,8 +268,8 @@ describe('payment-page.vue', () => {
|
||||||
describe('getPaymentType', () => {
|
describe('getPaymentType', () => {
|
||||||
test('Maps AFTERPAY -> hopPaymentMethods.AFTERPAY', () => {
|
test('Maps AFTERPAY -> hopPaymentMethods.AFTERPAY', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
useMainStore().order.payment.payInAdvanceType = paymentMethods.AFTERPAY;
|
useMainStore().order.payment.payInAdvanceType = paymentMethods.AFTERPAY;
|
||||||
const wrapper = setupMocks({});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const mapped = wrapper.vm.getPaymentType();
|
const mapped = wrapper.vm.getPaymentType();
|
||||||
|
|
@ -282,8 +280,8 @@ describe('payment-page.vue', () => {
|
||||||
|
|
||||||
test('Maps CREDIT_CARD -> hopPaymentMethods.CREDIT_CARD', () => {
|
test('Maps CREDIT_CARD -> hopPaymentMethods.CREDIT_CARD', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
useMainStore().order.payment.payInAdvanceType = paymentMethods.CREDIT_CARD;
|
useMainStore().order.payment.payInAdvanceType = paymentMethods.CREDIT_CARD;
|
||||||
const wrapper = setupMocks({});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const mapped = wrapper.vm.getPaymentType();
|
const mapped = wrapper.vm.getPaymentType();
|
||||||
|
|
@ -294,8 +292,8 @@ describe('payment-page.vue', () => {
|
||||||
|
|
||||||
test('Maps PAYPAL -> hopPaymentMethods.PAYPAL', () => {
|
test('Maps PAYPAL -> hopPaymentMethods.PAYPAL', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
useMainStore().order.payment.payInAdvanceType = paymentMethods.PAYPAL;
|
useMainStore().order.payment.payInAdvanceType = paymentMethods.PAYPAL;
|
||||||
const wrapper = setupMocks({});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const mapped = wrapper.vm.getPaymentType();
|
const mapped = wrapper.vm.getPaymentType();
|
||||||
|
|
@ -306,8 +304,8 @@ describe('payment-page.vue', () => {
|
||||||
|
|
||||||
test('Maps other values to self', () => {
|
test('Maps other values to self', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
useMainStore().order.payment.payInAdvanceType = 'SomeOtherText';
|
useMainStore().order.payment.payInAdvanceType = 'SomeOtherText';
|
||||||
const wrapper = setupMocks({});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const mapped = wrapper.vm.getPaymentType();
|
const mapped = wrapper.vm.getPaymentType();
|
||||||
|
|
@ -319,7 +317,7 @@ describe('payment-page.vue', () => {
|
||||||
|
|
||||||
describe('cart-dropdown', () => {
|
describe('cart-dropdown', () => {
|
||||||
test('Show cart dropdown if credit card', async () => {
|
test('Show cart dropdown if credit card', async () => {
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
wrapper.vm.paymentType = hopPaymentMethods.CREDIT_CARD;
|
wrapper.vm.paymentType = hopPaymentMethods.CREDIT_CARD;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -331,7 +329,7 @@ describe('payment-page.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('show cart dropdown if afterpay', async () => {
|
test('show cart dropdown if afterpay', async () => {
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
wrapper.vm.paymentType = hopPaymentMethods.AFTERPAY;
|
wrapper.vm.paymentType = hopPaymentMethods.AFTERPAY;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -343,7 +341,7 @@ describe('payment-page.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Hide cart dropdown if paypal', async () => {
|
test('Hide cart dropdown if paypal', async () => {
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
wrapper.vm.paymentType = hopPaymentMethods.PAYPAL;
|
wrapper.vm.paymentType = hopPaymentMethods.PAYPAL;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -359,7 +357,7 @@ describe('payment-page.vue', () => {
|
||||||
test('Is responsive if initial data changes', async () => {
|
test('Is responsive if initial data changes', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
// note: begins with payment-type = afterpay
|
// note: begins with payment-type = afterpay
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const preVal = wrapper.vm.isPaypal;
|
const preVal = wrapper.vm.isPaypal;
|
||||||
|
|
@ -384,7 +382,7 @@ describe('payment-page.vue', () => {
|
||||||
signature: 'SIGNATURE',
|
signature: 'SIGNATURE',
|
||||||
startDate: 'STARTDATE'
|
startDate: 'STARTDATE'
|
||||||
};
|
};
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
|
|
||||||
wrapper.vm.submitHopForm = jest.fn();
|
wrapper.vm.submitHopForm = jest.fn();
|
||||||
|
|
||||||
|
|
@ -403,7 +401,7 @@ describe('payment-page.vue', () => {
|
||||||
describe('submitHopForm', () => {
|
describe('submitHopForm', () => {
|
||||||
test('Submits form', async () => {
|
test('Submits form', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
|
|
||||||
wrapper.vm.$refs.hopForm.submit = jest.fn();
|
wrapper.vm.$refs.hopForm.submit = jest.fn();
|
||||||
wrapper.vm.$refs.paymentFrame = null;
|
wrapper.vm.$refs.paymentFrame = null;
|
||||||
|
|
@ -425,7 +423,7 @@ describe('payment-page.vue', () => {
|
||||||
data: 'afterpayClosed'
|
data: 'afterpayClosed'
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
|
|
||||||
wrapper.vm.backButtonAction = jest.fn();
|
wrapper.vm.backButtonAction = jest.fn();
|
||||||
|
|
||||||
|
|
@ -442,7 +440,7 @@ describe('payment-page.vue', () => {
|
||||||
data: 'creditCardSubmit'
|
data: 'creditCardSubmit'
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.vm.handleIFrameContentWindowMessage(event);
|
wrapper.vm.handleIFrameContentWindowMessage(event);
|
||||||
|
|
@ -456,7 +454,7 @@ describe('payment-page.vue', () => {
|
||||||
describe('UI Blocking', () => {
|
describe('UI Blocking', () => {
|
||||||
test('UI block appears when toggled', async () => {
|
test('UI block appears when toggled', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.vm.setUIBlock(true);
|
wrapper.vm.setUIBlock(true);
|
||||||
|
|
@ -471,7 +469,7 @@ describe('payment-page.vue', () => {
|
||||||
|
|
||||||
test("Don't propogate clicks from UI block", async () => {
|
test("Don't propogate clicks from UI block", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const wrapper = setupMocks({});
|
const { wrapper } = getMountedComponent(defaultOrder);
|
||||||
|
|
||||||
const outerDiv = wrapper.find('.container-fluid');
|
const outerDiv = wrapper.find('.container-fluid');
|
||||||
const clickFn = jest.fn();
|
const clickFn = jest.fn();
|
||||||
|
|
@ -497,7 +495,7 @@ describe('payment-page.vue', () => {
|
||||||
const queryString = {
|
const queryString = {
|
||||||
[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: paymentMethods.CREDIT_CARD
|
[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: paymentMethods.CREDIT_CARD
|
||||||
};
|
};
|
||||||
const wrapper = setupMocks({ queryString });
|
const { wrapper } = getMountedComponent(defaultOrder, {}, () => {}, queryString);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
||||||
|
|
@ -514,7 +512,7 @@ describe('payment-page.vue', () => {
|
||||||
const queryString = {
|
const queryString = {
|
||||||
[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: paymentMethods.AFTERPAY
|
[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: paymentMethods.AFTERPAY
|
||||||
};
|
};
|
||||||
const wrapper = setupMocks({ queryString });
|
const { wrapper } = getMountedComponent(defaultOrder, {}, () => {}, queryString);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
class="px-2">
|
class="px-2">
|
||||||
<hr :class="{'my-0': isCreditCard}">
|
<hr :class="{'my-0': isCreditCard}">
|
||||||
<cartDropdown
|
<cartDropdown
|
||||||
|
ref="cart"
|
||||||
:readOnly="true"
|
:readOnly="true"
|
||||||
:showDropdownHeader="true"
|
:showDropdownHeader="true"
|
||||||
:isInitiallyExpanded="true"
|
:isInitiallyExpanded="true"
|
||||||
|
|
@ -396,8 +397,8 @@ import issPageValues from '@/router/router-constants/issPage-values.js';
|
||||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||||
import settleAllPromises from '@/helpers/layout-helper';
|
import settleAllPromises from '@/helpers/layout-helper';
|
||||||
import { Form } from 'vee-validate';
|
import { Form } from 'vee-validate';
|
||||||
import baseMixin from '@/mixins/base-mixin.js';
|
|
||||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||||
|
import { getCartTotal } from '@/helpers/cart-helper';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
import iframeResize from 'iframe-resizer/js/iframeResizer.js';
|
import iframeResize from 'iframe-resizer/js/iframeResizer.js';
|
||||||
import externalUrls from '@/router/router-constants/externalUrl-values.js';
|
import externalUrls from '@/router/router-constants/externalUrl-values.js';
|
||||||
|
|
@ -410,6 +411,7 @@ import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
|
||||||
import queryStrings from '@/constants/query-strings';
|
import queryStrings from '@/constants/query-strings';
|
||||||
import alert from '@/ux-components/alert/alert.vue';
|
import alert from '@/ux-components/alert/alert.vue';
|
||||||
import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
|
import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
|
||||||
|
import { formatAmountInDollars } from '@/helpers/text-helper';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'payment-page',
|
name: 'payment-page',
|
||||||
|
|
@ -458,13 +460,10 @@ export default {
|
||||||
|
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
if (vm.$refs.cart) {
|
if (vm.$refs.cart) {
|
||||||
const { cartItems } = vm.$refs.cart;
|
const cartItems = vm.$refs.cart.allCartItems;
|
||||||
vm.getPayInAdvanceLineItems(cartItems);
|
vm.getPayInAdvanceLineItems(cartItems);
|
||||||
} else {
|
|
||||||
vm.getMockPiaLineItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.fetchSignatureInfo(resultMap.paymentSignature);
|
vm.fetchSignatureInfo(resultMap.paymentSignature);
|
||||||
|
|
@ -704,21 +703,11 @@ export default {
|
||||||
getPayInAdvanceFormattedLineItem(itemName, price, quantity) {
|
getPayInAdvanceFormattedLineItem(itemName, price, quantity) {
|
||||||
return `${itemName}|${price}|${quantity}`;
|
return `${itemName}|${price}|${quantity}`;
|
||||||
},
|
},
|
||||||
getMockPiaLineItems() {
|
|
||||||
let lineItems = [];
|
|
||||||
lineItems = [
|
|
||||||
this.getPayInAdvanceFormattedLineItem('Parts and labor', 0, 1)
|
|
||||||
];
|
|
||||||
lineItems.push(this.getPayInAdvanceFormattedLineItem('New wiper blades', 75.22, 1));
|
|
||||||
lineItems.push(this.getPayInAdvanceFormattedLineItem('Recycling', 37.6, 1));
|
|
||||||
|
|
||||||
this.payInAdvanceLineItems = lineItems.join('||');
|
|
||||||
},
|
|
||||||
getAmountDue() {
|
getAmountDue() {
|
||||||
return baseMixin.methods.getAmountDue(useMainStore().lineItems);
|
return getCartTotal(useMainStore().order);
|
||||||
},
|
},
|
||||||
getDisplayAmountDue() {
|
getDisplayAmountDue() {
|
||||||
return baseMixin.methods.getDisplayAmountDue(useMainStore().lineItems);
|
return formatAmountInDollars(this.getAmountDue());
|
||||||
},
|
},
|
||||||
fetchSignatureInfo(signatureInfo) {
|
fetchSignatureInfo(signatureInfo) {
|
||||||
this.authToken = signatureInfo.token;
|
this.authToken = signatureInfo.token;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ import buttonQuestion from '@/digital-components/button-question/button-question
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import { deepClone } from '@/helpers/object-helper';
|
import { deepClone } from '@/helpers/object-helper';
|
||||||
|
import { formatAmountInDollars } from '@/helpers/text-helper';
|
||||||
|
import { getPriceOfLineItem } from '@/helpers/price-calculator';
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
import { defineRule, useField } from 'vee-validate';
|
import { defineRule, useField } from 'vee-validate';
|
||||||
|
|
@ -421,7 +423,7 @@ export default {
|
||||||
},
|
},
|
||||||
getPremiumAppointmentTimeSlot(timeSlotData) {
|
getPremiumAppointmentTimeSlot(timeSlotData) {
|
||||||
const formattedPrice =
|
const formattedPrice =
|
||||||
`+$${this.getTotalLineItemPrice(this.premiumAppointmentFee).toFixed(2)}`;
|
`+${formatAmountInDollars(getPriceOfLineItem(this.premiumAppointmentFee))}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Unique value is required for each <input> and the premium appoinment shares an id
|
// Unique value is required for each <input> and the premium appoinment shares an id
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import servicePackageRadio from '@/layouts/service-packages/service-package-ques
|
||||||
import partTypeStrings from '@/constants/part-type-strings';
|
import partTypeStrings from '@/constants/part-type-strings';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
import allGlassPartsAndItemsHavePrices from '@/layouts/service-packages/service-package-helper/service-package-helper';
|
import allGlassPartsAndItemsHavePrices from '@/layouts/service-packages/service-package-helper/service-package-helper';
|
||||||
|
import { getPriceOfLineItem } from '@/helpers/price-calculator';
|
||||||
|
|
||||||
const glassLocations = damageLocationsSelected;
|
const glassLocations = damageLocationsSelected;
|
||||||
|
|
||||||
|
|
@ -186,7 +187,7 @@ export default {
|
||||||
&& item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER)
|
&& item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER)
|
||||||
|| (priceRearWipers && item.partType.toUpperCase() === partTypeStrings.REAR_WIPER)
|
|| (priceRearWipers && item.partType.toUpperCase() === partTypeStrings.REAR_WIPER)
|
||||||
) {
|
) {
|
||||||
vapsPrice += this.getTotalLineItemPrice(item);
|
vapsPrice += getPriceOfLineItem(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return vapsPrice;
|
return vapsPrice;
|
||||||
|
|
@ -205,7 +206,7 @@ export default {
|
||||||
|| (priceRainDefense
|
|| (priceRainDefense
|
||||||
&& item.partType.toUpperCase() === partTypeStrings.RAIN_DEFENSE)
|
&& item.partType.toUpperCase() === partTypeStrings.RAIN_DEFENSE)
|
||||||
) {
|
) {
|
||||||
vapsPrice += this.getTotalLineItemPrice(item);
|
vapsPrice += getPriceOfLineItem(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return vapsPrice;
|
return vapsPrice;
|
||||||
|
|
@ -309,9 +310,6 @@ export default {
|
||||||
const glassLocationMatches =
|
const glassLocationMatches =
|
||||||
store.order.damage.glassToReplace?.filter((glassToReplace) => glassToReplace.glassLocation === glassLocation) ?? [];
|
store.order.damage.glassToReplace?.filter((glassToReplace) => glassToReplace.glassLocation === glassLocation) ?? [];
|
||||||
return !!glassLocationMatches.length;
|
return !!glassLocationMatches.length;
|
||||||
},
|
|
||||||
getTotalLineItemPrice(lineItem) {
|
|
||||||
return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -36,62 +36,6 @@ export default {
|
||||||
savePageDataToStore(page, data) {
|
savePageDataToStore(page, data) {
|
||||||
useMainStore().updatePageData({ page, data });
|
useMainStore().updatePageData({ page, data });
|
||||||
},
|
},
|
||||||
getTotalPriceOfAllLineItemsAndChildParts(lineItems, includeTax) {
|
|
||||||
let totalPrice = 0;
|
|
||||||
lineItems.forEach((lineItem) => {
|
|
||||||
totalPrice += this.getTotalLineItemPrice(lineItem, includeTax);
|
|
||||||
if (lineItem.childParts) {
|
|
||||||
totalPrice += this.getTotalPriceOfAllLineItemsAndChildParts(
|
|
||||||
lineItem.childParts,
|
|
||||||
includeTax
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return totalPrice;
|
|
||||||
},
|
|
||||||
getTotalLineItemPrice(lineItem, includeTax) {
|
|
||||||
if (includeTax) {
|
|
||||||
return (
|
|
||||||
lineItem.kitPrice
|
|
||||||
+ lineItem.laborAmount
|
|
||||||
+ lineItem.sellingPrice
|
|
||||||
+ lineItem.salesTax
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice;
|
|
||||||
},
|
|
||||||
getDisplayAmountDue(lineItems) {
|
|
||||||
return this.getAmountDue(lineItems).toLocaleString('en-US', {
|
|
||||||
style: 'currency',
|
|
||||||
currency: 'USD'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getAmountDue(lineItems) {
|
|
||||||
if (!useMainStore().isNoComp && !useMainStore().isITAC) {
|
|
||||||
return useMainStore().order.currentDeductible;
|
|
||||||
}
|
|
||||||
|
|
||||||
let amountDue = 0;
|
|
||||||
if (lineItems.glassParts) {
|
|
||||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
|
|
||||||
lineItems.glassParts,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (lineItems.supportingItems) {
|
|
||||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
|
|
||||||
lineItems.supportingItems,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (lineItems.vaps) {
|
|
||||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(lineItems.vaps, false);
|
|
||||||
}
|
|
||||||
if (lineItems.promos) {
|
|
||||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(lineItems.promos, false);
|
|
||||||
}
|
|
||||||
return ((amountDue * 100) / 100).toFixed(2);
|
|
||||||
},
|
|
||||||
scrollToPageTop() {
|
scrollToPageTop() {
|
||||||
const container = document.getElementsByClassName('fade-on-route-transition')[0];
|
const container = document.getElementsByClassName('fade-on-route-transition')[0];
|
||||||
container.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
|
container.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ import {
|
||||||
import partTypeStrings from '@/constants/part-type-strings';
|
import partTypeStrings from '@/constants/part-type-strings';
|
||||||
import bailoutMessage from '@/constants/bailoutMessage';
|
import bailoutMessage from '@/constants/bailoutMessage';
|
||||||
import bailoutCode from '@/constants/bailoutCode';
|
import bailoutCode from '@/constants/bailoutCode';
|
||||||
|
import partNumberStrings from '@/constants/part-number-strings';
|
||||||
|
import { getLineItemsFlattened } from '@/helpers/line-items-helper';
|
||||||
|
import { buildQueryStringParameterFromArrayOfComplexObjects, getLineItemQueryString } from '@/helpers/querystring-helper';
|
||||||
|
|
||||||
const storeId = 'main';
|
const storeId = 'main';
|
||||||
|
|
||||||
|
|
@ -149,8 +152,9 @@ export const getDefaultState = () => ({
|
||||||
glassParts: null,
|
glassParts: null,
|
||||||
otherParts: null,
|
otherParts: null,
|
||||||
supportingItems: null,
|
supportingItems: null,
|
||||||
|
feeItems: [],
|
||||||
vaps: null,
|
vaps: null,
|
||||||
mobileFee: null
|
serverData: null
|
||||||
},
|
},
|
||||||
payment: {
|
payment: {
|
||||||
insuranceCoverage: {
|
insuranceCoverage: {
|
||||||
|
|
@ -273,6 +277,11 @@ export const useMainStore = defineStore({
|
||||||
policy: (state) => state.order.policy,
|
policy: (state) => state.order.policy,
|
||||||
hasExactlyOneChip: () => state.order.damage.numberOfChips === 1,
|
hasExactlyOneChip: () => state.order.damage.numberOfChips === 1,
|
||||||
isPolicyVehicle: () => state.order.vehicle.policyVehicleId != null,
|
isPolicyVehicle: () => state.order.vehicle.policyVehicleId != null,
|
||||||
|
hasWindshieldReplacement: (s) => {
|
||||||
|
const { damage, lineItems } = s.order;
|
||||||
|
return !damage.isRepair
|
||||||
|
&& (lineItems.glassParts?.some((gp) => gp.partType === partTypeStrings.WINDSHIELD) ?? false);
|
||||||
|
},
|
||||||
hasAnyNonWindshieldGlassParts: (s) => !s.order.policy.isDamageGlassOnly,
|
hasAnyNonWindshieldGlassParts: (s) => !s.order.policy.isDamageGlassOnly,
|
||||||
isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|
isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|
||||||
|| state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP,
|
|| state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP,
|
||||||
|
|
@ -848,8 +857,9 @@ export const useMainStore = defineStore({
|
||||||
let lineItems = [
|
let lineItems = [
|
||||||
...(order.lineItems.supportingItems ?? []),
|
...(order.lineItems.supportingItems ?? []),
|
||||||
...(order.lineItems.vaps ?? []),
|
...(order.lineItems.vaps ?? []),
|
||||||
...getFlattenedArrayOfLineItemsWithChildParts(order.lineItems.glassParts)
|
...(order.lineItems.glassParts)
|
||||||
];
|
];
|
||||||
|
lineItems = getLineItemsFlattened(lineItems);
|
||||||
lineItems = lineItems.map((lineItem) => ({
|
lineItems = lineItems.map((lineItem) => ({
|
||||||
partNumber: lineItem.partNumber,
|
partNumber: lineItem.partNumber,
|
||||||
partType: lineItem.partType
|
partType: lineItem.partType
|
||||||
|
|
@ -909,8 +919,9 @@ export const useMainStore = defineStore({
|
||||||
let lineItems = [
|
let lineItems = [
|
||||||
...(order.lineItems.supportingItems ?? []),
|
...(order.lineItems.supportingItems ?? []),
|
||||||
...(order.lineItems.vaps ?? []),
|
...(order.lineItems.vaps ?? []),
|
||||||
...getFlattenedArrayOfLineItemsWithChildParts(order.lineItems.glassParts)
|
...(order.lineItems.glassParts ?? [])
|
||||||
];
|
];
|
||||||
|
lineItems = getLineItemsFlattened(lineItems);
|
||||||
lineItems = lineItems.map((lineItem) => ({
|
lineItems = lineItems.map((lineItem) => ({
|
||||||
partNumber: lineItem.partNumber,
|
partNumber: lineItem.partNumber,
|
||||||
partType: lineItem.partType
|
partType: lineItem.partType
|
||||||
|
|
@ -1044,16 +1055,17 @@ export const useMainStore = defineStore({
|
||||||
this.order.serviceLocation.zipCodeCtu = zipInfo.data.zipCodeCtu;
|
this.order.serviceLocation.zipCodeCtu = zipInfo.data.zipCodeCtu;
|
||||||
}
|
}
|
||||||
const ctuToUse = this.order.serviceLocation.zipCodeCtu;
|
const ctuToUse = this.order.serviceLocation.zipCodeCtu;
|
||||||
const availableLineItemsFormattedForRequest = getLineItemQueryStringForPricing(availableLineItems);
|
|
||||||
const deductibleToUse = this.order.currentDeductible ?? 0;
|
const deductibleToUse = this.order.currentDeductible ?? 0;
|
||||||
|
|
||||||
|
const lineItemsQueryString = getLineItemQueryString(availableLineItems, 'lineItems');
|
||||||
|
|
||||||
let queryString =
|
let queryString =
|
||||||
`ParentAccountNumber=${this.order.accountNumber}`
|
`ParentAccountNumber=${this.order.accountNumber}`
|
||||||
+ `&BillToAccountNumber=${this.billToNumberToUse}`
|
+ `&BillToAccountNumber=${this.billToNumberToUse}`
|
||||||
+ `&CTU=${ctuToUse}`
|
+ `&CTU=${ctuToUse}`
|
||||||
+ `&Deductible=${deductibleToUse}`
|
+ `&Deductible=${deductibleToUse}`
|
||||||
+ `&ZipCode=${zipCodeToUse}`
|
+ `&ZipCode=${zipCodeToUse}`
|
||||||
+ `${availableLineItemsFormattedForRequest}`;
|
+ `${lineItemsQueryString}`;
|
||||||
|
|
||||||
const lineItemServerData = this.order.lineItems?.serverData;
|
const lineItemServerData = this.order.lineItems?.serverData;
|
||||||
if (lineItemServerData) {
|
if (lineItemServerData) {
|
||||||
|
|
@ -1069,8 +1081,13 @@ export const useMainStore = defineStore({
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.data?.lineItems) {
|
const { lineItems, serverData } = response.data;
|
||||||
const retAvailableLineItems = addPricesToLineItems(availableLineItems, response.data.lineItems);
|
if (serverData) {
|
||||||
|
this.order.lineItems.serverData = serverData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lineItems) {
|
||||||
|
const retAvailableLineItems = addPricesToLineItems(availableLineItems, lineItems);
|
||||||
return retAvailableLineItems;
|
return retAvailableLineItems;
|
||||||
}
|
}
|
||||||
return availableLineItems;
|
return availableLineItems;
|
||||||
|
|
@ -1086,10 +1103,7 @@ export const useMainStore = defineStore({
|
||||||
},
|
},
|
||||||
|
|
||||||
getServiceabilityDetails({ serviceZipCode }) {
|
getServiceabilityDetails({ serviceZipCode }) {
|
||||||
const lineItemsWithOnlyPartNumbers = this.order.lineItems.supportingItems.map((lineItem) => ({
|
const lineItems = getLineItemQueryString(this.order.lineItems.supportingItems, 'lineItems');
|
||||||
partNumber: lineItem.partNumber
|
|
||||||
}));
|
|
||||||
const lineItems = buildQueryStringParameterFromArrayOfComplexObjects(lineItemsWithOnlyPartNumbers, 'lineItems');
|
|
||||||
|
|
||||||
const { vehicle } = this.order;
|
const { vehicle } = this.order;
|
||||||
const { carId } = vehicle;
|
const { carId } = vehicle;
|
||||||
|
|
@ -1100,7 +1114,7 @@ export const useMainStore = defineStore({
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetServiceabilityDetails.method,
|
method: endpoints.GetServiceabilityDetails.method,
|
||||||
endpoint: `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&${lineItems}&${glassPieces}`
|
endpoint: `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}${lineItems}&${glassPieces}`
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mapTaxedLineItemsToStoreFormat(availableLineItems, storeLineItems) {
|
mapTaxedLineItemsToStoreFormat(availableLineItems, storeLineItems) {
|
||||||
|
|
@ -1209,6 +1223,10 @@ export const useMainStore = defineStore({
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.hasSubmittedOrder()) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
const loadedFromDupeCheck = !!(this.order.loadedFromDupeCheck && !this.order.loadedSessionClearedPreviousData);
|
const loadedFromDupeCheck = !!(this.order.loadedFromDupeCheck && !this.order.loadedSessionClearedPreviousData);
|
||||||
|
|
||||||
const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace);
|
const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace);
|
||||||
|
|
@ -1596,20 +1614,51 @@ export const useMainStore = defineStore({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let parts = partsData;
|
// Process Recycle Fee
|
||||||
if (!this.isNoComp && !this.isITAC) {
|
this.updateRecycleFee(partsData.find((rf) => rf.partNumber === partNumberStrings.RECYCLE_FEE));
|
||||||
parts = parts.filter((i) => i.partNumber !== partTypeStrings.RECYCLE_FEE);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.order.lineItems.supportingItems = parts;
|
// Remove RecycleFee from supported items as it's saved in feeItems;
|
||||||
|
this.order.lineItems.supportingItems = partsData.filter((i) => i.partNumber !== partNumberStrings.RECYCLE_FEE);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateVaps(partsData) {
|
updateVaps(partsData) {
|
||||||
this.order.lineItems.vaps = partsData;
|
this.order.lineItems.vaps = partsData;
|
||||||
},
|
},
|
||||||
|
|
||||||
updateMobileFee(mobileFee) {
|
updateMobileFee(fee) {
|
||||||
this.order.lineItems.mobileFee = mobileFee;
|
// Mobile Fee is only added for NO COMP or ITAC
|
||||||
|
if (fee && !this.isUnverified && (this.isNoComp || this.isITAC)) {
|
||||||
|
this.addPartTypeFeeItem(fee, partTypeStrings.MOBILE_FEE);
|
||||||
|
} else {
|
||||||
|
this.addPartTypeFeeItem(null, partTypeStrings.MOBILE_FEE);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateRecycleFee(fee) {
|
||||||
|
// Recycle Fee is only added for NO COMP or ITAC and has Windshield Replacement
|
||||||
|
if (fee && !this.isUnverified && (this.isNoComp || this.isITAC) && this.hasWindshieldReplacement) {
|
||||||
|
this.addPartNumberFeeItem(fee, partNumberStrings.RECYCLE_FEE);
|
||||||
|
} else {
|
||||||
|
this.addPartNumberFeeItem(null, partNumberStrings.RECYCLE_FEE);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addPartNumberFeeItem(feeItem, partNumber) {
|
||||||
|
this.addFeeItem(feeItem, (fi) => fi.partNumber !== partNumber);
|
||||||
|
},
|
||||||
|
|
||||||
|
addPartTypeFeeItem(feeItem, partType) {
|
||||||
|
this.addFeeItem(feeItem, (fi) => fi.partType !== partType);
|
||||||
|
},
|
||||||
|
|
||||||
|
addFeeItem(feeItem, filter) {
|
||||||
|
let { feeItems } = this.order.lineItems;
|
||||||
|
// Remove all fee items with the given filter
|
||||||
|
feeItems = feeItems.filter(filter);
|
||||||
|
if (feeItem) {
|
||||||
|
feeItems.push(feeItem);
|
||||||
|
}
|
||||||
|
this.order.lineItems.feeItems = feeItems;
|
||||||
},
|
},
|
||||||
|
|
||||||
async setPriceAndSalesTaxForOrderLineItems() {
|
async setPriceAndSalesTaxForOrderLineItems() {
|
||||||
|
|
@ -1617,16 +1666,13 @@ export const useMainStore = defineStore({
|
||||||
...(this.order.lineItems.supportingItems ?? []),
|
...(this.order.lineItems.supportingItems ?? []),
|
||||||
...(this.order.lineItems.glassParts ?? []),
|
...(this.order.lineItems.glassParts ?? []),
|
||||||
...(this.order.lineItems.otherParts ?? []),
|
...(this.order.lineItems.otherParts ?? []),
|
||||||
...(this.order.lineItems.vaps ?? [])
|
...(this.order.lineItems.vaps ?? []),
|
||||||
|
...(this.order.lineItems.feeItems ?? []
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
if (this.order.lineItems.mobileFee != null) {
|
await this.getPriceOrderItems(lineItemsToTax);
|
||||||
lineItemsToTax.push(this.order.lineItems.mobileFee);
|
await this.getTaxOrderItems(lineItemsToTax);
|
||||||
}
|
|
||||||
|
|
||||||
const pricedLineItemsToTax = await this.getPriceOrderItems(lineItemsToTax);
|
|
||||||
|
|
||||||
this.taxOrderItemsAndSaveServerData(pricedLineItemsToTax);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updateVehicle(vehicle) {
|
updateVehicle(vehicle) {
|
||||||
|
|
@ -1734,6 +1780,8 @@ export const useMainStore = defineStore({
|
||||||
resetGlassPartsState() {
|
resetGlassPartsState() {
|
||||||
this.order.lineItems.glassParts = null;
|
this.order.lineItems.glassParts = null;
|
||||||
this.order.lineItems.supportingItems = null;
|
this.order.lineItems.supportingItems = null;
|
||||||
|
this.order.lineItems.feeItems = [];
|
||||||
|
this.order.lineItems.serverData = null;
|
||||||
this.order.damage.partQuestionAnswers = null;
|
this.order.damage.partQuestionAnswers = null;
|
||||||
this.order.damage.moldingQuestionAnswers = null;
|
this.order.damage.moldingQuestionAnswers = null;
|
||||||
this.order.damage.capabilityQuestionAnswers = null;
|
this.order.damage.capabilityQuestionAnswers = null;
|
||||||
|
|
@ -1963,7 +2011,7 @@ export const useMainStore = defineStore({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Tax order actions
|
// Tax order actions
|
||||||
async taxOrderItemsAndSaveServerData(pricedLineItems) {
|
async getTaxOrderItems(pricedLineItems) {
|
||||||
const { order } = this;
|
const { order } = this;
|
||||||
const { serviceLocation } = order;
|
const { serviceLocation } = order;
|
||||||
const { providerNumber } = serviceLocation.provider;
|
const { providerNumber } = serviceLocation.provider;
|
||||||
|
|
@ -1972,39 +2020,27 @@ export const useMainStore = defineStore({
|
||||||
const serviceLocationState = serviceLocation.state;
|
const serviceLocationState = serviceLocation.state;
|
||||||
const serviceLocationZipCode = serviceLocation.zipCode;
|
const serviceLocationZipCode = serviceLocation.zipCode;
|
||||||
|
|
||||||
const flattenedLineItemsWithChildParts = getFlattenedArrayOfLineItemsWithChildParts(pricedLineItems);
|
const lineItemsQueryString = getLineItemQueryString(pricedLineItems, 'lineItems');
|
||||||
|
|
||||||
const lineItemsWithOnlyPriceInfo = flattenedLineItemsWithChildParts.map((lineItem) => ({
|
|
||||||
partNumber: lineItem.partNumber,
|
|
||||||
laborAmount: lineItem.laborAmount ?? 0,
|
|
||||||
kitPrice: lineItem.kitPrice ?? 0,
|
|
||||||
sellingPrice: lineItem.sellingPrice ?? 0
|
|
||||||
}));
|
|
||||||
|
|
||||||
const pricedLineItemsFormattedForRequest = buildQueryStringParameterFromArrayOfComplexObjects(
|
|
||||||
lineItemsWithOnlyPriceInfo,
|
|
||||||
'lineItems'
|
|
||||||
);
|
|
||||||
|
|
||||||
let queryString = '';
|
let queryString = '';
|
||||||
if (appointmentType === AppointmentTypeStrings.MOBILE
|
if (appointmentType === AppointmentTypeStrings.MOBILE
|
||||||
|| appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
|| appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
|
||||||
queryString =
|
queryString =
|
||||||
`ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}`
|
`ParentAccountNumber=${this.order.accountNumber}`
|
||||||
+ `&BillToAccountNumber=${this.billToNumberToUse}`
|
+ `&BillToAccountNumber=${this.billToNumberToUse}`
|
||||||
+ `&ProviderNumber=${providerNumber}`
|
+ `&ProviderNumber=${providerNumber}`
|
||||||
+ `&AppointmentType=${appointmentType}`
|
+ `&AppointmentType=${appointmentType}`
|
||||||
+ `&ServiceLocation.City=${serviceLocationCity}`
|
+ `&ServiceLocation.City=${serviceLocationCity}`
|
||||||
+ `&ServiceLocation.State=${serviceLocationState}`
|
+ `&ServiceLocation.State=${serviceLocationState}`
|
||||||
+ `&ServiceLocation.ZipCode=${serviceLocationZipCode}`
|
+ `&ServiceLocation.ZipCode=${serviceLocationZipCode}`
|
||||||
+ `&${pricedLineItemsFormattedForRequest}`;
|
+ `${lineItemsQueryString}`;
|
||||||
} else {
|
} else {
|
||||||
queryString =
|
queryString =
|
||||||
`ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}`
|
`ParentAccountNumber=${this.order.accountNumber}`
|
||||||
+ `&BillToAccountNumber=${this.billToNumberToUse}`
|
+ `&BillToAccountNumber=${this.billToNumberToUse}`
|
||||||
+ `&ProviderNumber=${providerNumber}`
|
+ `&ProviderNumber=${providerNumber}`
|
||||||
+ `&AppointmentType=${appointmentType}`
|
+ `&AppointmentType=${appointmentType}`
|
||||||
+ `&${pricedLineItemsFormattedForRequest}`;
|
+ `${lineItemsQueryString}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lineItemServerData = this.order.lineItems.serverData;
|
const lineItemServerData = this.order.lineItems.serverData;
|
||||||
|
|
@ -2373,7 +2409,6 @@ export const useMainStore = defineStore({
|
||||||
resetPartsAndDependencies() {
|
resetPartsAndDependencies() {
|
||||||
this.resetGlassPartsState();
|
this.resetGlassPartsState();
|
||||||
this.updateVaps(null);
|
this.updateVaps(null);
|
||||||
this.updateMobileFee(null);
|
|
||||||
|
|
||||||
this.resetServiceLocationAndDependencies();
|
this.resetServiceLocationAndDependencies();
|
||||||
},
|
},
|
||||||
|
|
@ -2415,6 +2450,8 @@ export const useMainStore = defineStore({
|
||||||
const { experiments } = this.applicationUser;
|
const { experiments } = this.applicationUser;
|
||||||
const { issConfig } = this;
|
const { issConfig } = this;
|
||||||
|
|
||||||
|
submittedOrder.isUnverified = this.isUnverified;
|
||||||
|
|
||||||
// set to local storage
|
// set to local storage
|
||||||
window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder));
|
window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder));
|
||||||
|
|
||||||
|
|
@ -2519,10 +2556,8 @@ function addPricesToLineItems(lineItems, pricingLineItems) {
|
||||||
addPricesToLineItems(lineItem.childParts, pricingLineItems);
|
addPricesToLineItems(lineItem.childParts, pricingLineItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
const lineItemIndex = pricingLineItems.findIndex((pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber);
|
const pricedLineItem = pricingLineItems.find((pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber);
|
||||||
|
if (pricedLineItem) {
|
||||||
if (lineItemIndex > -1) {
|
|
||||||
const pricedLineItem = pricingLineItems[lineItemIndex];
|
|
||||||
lineItem.laborAmount = pricedLineItem.laborAmount;
|
lineItem.laborAmount = pricedLineItem.laborAmount;
|
||||||
lineItem.sellingPrice = pricedLineItem.sellingPrice;
|
lineItem.sellingPrice = pricedLineItem.sellingPrice;
|
||||||
lineItem.kitPrice = pricedLineItem.kitPrice;
|
lineItem.kitPrice = pricedLineItem.kitPrice;
|
||||||
|
|
@ -2546,42 +2581,6 @@ function addTaxesToPricedLineItems(pricedLineItems, taxingLineItems = []) {
|
||||||
return pricedLineItems;
|
return pricedLineItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLineItemQueryStringForPricing(lineItems) {
|
|
||||||
return lineItems.map((lineItem, index) => {
|
|
||||||
let queryStringSnippet = `&LineItems[${index}].partNumber=${lineItem.partNumber}`;
|
|
||||||
if (lineItem.childParts) {
|
|
||||||
queryStringSnippet += getLineItemQueryStringForPricing(lineItem.childParts);
|
|
||||||
}
|
|
||||||
|
|
||||||
return queryStringSnippet;
|
|
||||||
}).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFlattenedArrayOfLineItemsWithChildParts(lineItems) {
|
|
||||||
let flattenedArray = [];
|
|
||||||
lineItems?.forEach((lineItem) => {
|
|
||||||
flattenedArray.push(lineItem);
|
|
||||||
if (lineItem.childParts) {
|
|
||||||
flattenedArray = [
|
|
||||||
...flattenedArray,
|
|
||||||
...getFlattenedArrayOfLineItemsWithChildParts(lineItem.childParts)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return flattenedArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildQueryStringParameterFromArrayOfComplexObjects(arrayOfObjects, parameterName) {
|
|
||||||
let queryStringParameter = '';
|
|
||||||
for (let i = 0; i < arrayOfObjects.length; i++) {
|
|
||||||
for (const [key, value] of Object.entries(arrayOfObjects[i])) {
|
|
||||||
queryStringParameter += `${parameterName}[${i}].${key}=${value}&`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Remove trailing &
|
|
||||||
return queryStringParameter.slice(0, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertGlassPieceToBackEndCompatibleFormat(glassPieces) {
|
function convertGlassPieceToBackEndCompatibleFormat(glassPieces) {
|
||||||
return glassPieces.map((glassPiece) => ({
|
return glassPieces.map((glassPiece) => ({
|
||||||
location: glassPiece.glassLocation,
|
location: glassPiece.glassLocation,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue