SSR-1146. Payment Method page: Add sales tax to the cart-dropdown component. (#604)
This commit is contained in:
parent
ff047d7e15
commit
d02ac7fb50
6 changed files with 260 additions and 58 deletions
|
|
@ -44,7 +44,8 @@ module.exports = {
|
|||
math: 'always'
|
||||
}],
|
||||
'import/extensions': ['error', 'always', { js: 'ignorePackages' }],
|
||||
'no-param-reassign': ['error', { props: true, ignorePropertyModificationsFor: ['item'] }]
|
||||
'no-param-reassign': ['error', { props: true, ignorePropertyModificationsFor: ['item'] }],
|
||||
'no-restricted-syntax': ['off', 'ForOfStatement']
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,7 @@
|
|||
|
||||
exports[`cart-dropdown component initial data rendered as expected 1`] = `
|
||||
Object {
|
||||
"baseServiceLineItems": Array [],
|
||||
"deductible": null,
|
||||
"glassToReplace": Array [],
|
||||
"isExpanded": false,
|
||||
"isRepair": null,
|
||||
"vapsInOrder": Array [],
|
||||
"widget": Object {
|
||||
"amountDue": "AmountDueTextWidget",
|
||||
"basePrice": "BasePriceWidget",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
|
|||
|
||||
// Supporting Files
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||
import { useMainStore } from '@/store';
|
||||
import { useMainStore, getDefaultState } from '@/store';
|
||||
import coverageStatuses from '@/constants/coverage-statuses';
|
||||
import { formatAmountInDollars } from '@/helpers/text-helper.js';
|
||||
import partTypeStrings from '@/constants/part-type-strings';
|
||||
|
|
@ -455,7 +455,193 @@ describe('cart-dropdown component', () => {
|
|||
// TODO when method implemented
|
||||
});
|
||||
describe('salesTax', () => {
|
||||
// TODO when method implemented
|
||||
test('salesTax is treated as 0 when line items are null', () => {
|
||||
// Arrange
|
||||
const storeData = getDefaultState();
|
||||
storeData.order.lineItems.glassParts = null;
|
||||
storeData.order.lineItems.otherParts = null;
|
||||
storeData.order.lineItems.supportingItems = null;
|
||||
storeData.order.lineItems.vaps = null;
|
||||
|
||||
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 = getDefaultState();
|
||||
storeData.order.lineItems.glassParts = [
|
||||
{ partType: 'mock', salesTax: null },
|
||||
{ partType: 'mock', salesTax: undefined }
|
||||
];
|
||||
storeData.order.lineItems.supportingItems = [
|
||||
{ partType: 'mock', salesTax: null },
|
||||
{ partType: 'mock', salesTax: undefined }
|
||||
];
|
||||
storeData.order.lineItems.vaps = [
|
||||
{ partType: 'mock', salesTax: null },
|
||||
{ partType: 'mock', salesTax: undefined }
|
||||
];
|
||||
|
||||
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 = getDefaultState();
|
||||
storeData.order.lineItems.glassParts = [
|
||||
{ partType: 'mock', salesTax: 10 }
|
||||
];
|
||||
storeData.order.lineItems.vaps = [];
|
||||
storeData.order.payment.insuranceCoverage.isVerified = false;
|
||||
|
||||
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 = getDefaultState();
|
||||
storeData.order.lineItems.glassParts = [
|
||||
{ partType: 'mock', salesTax: 10 }
|
||||
];
|
||||
storeData.order.lineItems.vaps = [
|
||||
{ partType: 'mock', salesTax: 1 },
|
||||
{ partType: 'mock', salesTax: 2 }
|
||||
];
|
||||
storeData.order.payment.insuranceCoverage.isVerified = false;
|
||||
|
||||
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 = getDefaultState();
|
||||
storeData.order.currentDeductible = 250;
|
||||
storeData.order.lineItems.glassParts = [
|
||||
{ partType: 'mock', salesTax: 10, sellingPrice: 150 }
|
||||
];
|
||||
storeData.order.lineItems.supportingItems = [
|
||||
{ partNumber: partNumberStrings.RECYCLE_FEE, partType: 'mock', salesTax: 10, sellingPrice: 39.99 }
|
||||
];
|
||||
storeData.order.lineItems.vaps = null;
|
||||
storeData.order.payment.insuranceCoverage.isVerified = 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 = getDefaultState();
|
||||
storeData.order.currentDeductible = 250;
|
||||
storeData.order.lineItems.glassParts = [
|
||||
{ partType: 'mock', salesTax: 10, sellingPrice: 100 }
|
||||
];
|
||||
storeData.order.lineItems.otherParts = [
|
||||
{ partType: 'mock', salesTax: 10, kitPrice: 100 }
|
||||
];
|
||||
storeData.order.lineItems.supportingItems = [
|
||||
{ partNumber: partNumberStrings.RECYCLE_FEE, partType: 'mock', salesTax: 10, sellingPrice: 39.99 },
|
||||
{ partType: 'mock', salesTax: 10, kitPrice: 100 }
|
||||
];
|
||||
storeData.order.lineItems.vaps = [
|
||||
{ partType: 'mock', salesTax: 2 },
|
||||
{ partType: 'mock', salesTax: 3 }
|
||||
];
|
||||
storeData.order.payment.insuranceCoverage.isVerified = 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 = getDefaultState();
|
||||
storeData.order.currentDeductible = 0;
|
||||
storeData.order.lineItems.glassParts = [
|
||||
{ partType: 'mock', salesTax: 10, sellingPrice: 100 }
|
||||
];
|
||||
storeData.order.lineItems.otherParts = [
|
||||
{ partType: 'mock', salesTax: 10, kitPrice: 100 }
|
||||
];
|
||||
storeData.order.lineItems.supportingItems = [
|
||||
{ partType: 'mock', salesTax: 10, kitPrice: 100 }
|
||||
];
|
||||
storeData.order.lineItems.vaps = [
|
||||
{ partType: 'mock', salesTax: 5 }
|
||||
];
|
||||
storeData.order.payment.insuranceCoverage.isVerified = true;
|
||||
storeData.order.policy.isITAC = 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 = getDefaultState();
|
||||
storeData.order.currentDeductible = 0;
|
||||
storeData.order.lineItems.glassParts = [
|
||||
{ partType: 'mock', salesTax: 10, sellingPrice: 100 }
|
||||
];
|
||||
storeData.order.lineItems.otherParts = [
|
||||
{ partType: 'mock', salesTax: 10, kitPrice: 100 }
|
||||
];
|
||||
storeData.order.lineItems.supportingItems = [
|
||||
{ partType: 'mock', salesTax: 10, kitPrice: 100 }
|
||||
];
|
||||
storeData.order.lineItems.vaps = [
|
||||
{ partType: 'mock', salesTax: 5 }
|
||||
];
|
||||
storeData.order.payment.insuranceCoverage.isVerified = true;
|
||||
storeData.order.policy.noCoverage = true;
|
||||
|
||||
const { wrapper } = getMountedComponent(storeData);
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.salesTax;
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(35);
|
||||
});
|
||||
});
|
||||
describe('availableLineItems', () => {
|
||||
test('returns expected when glassParts null', async () => {
|
||||
|
|
@ -997,19 +1183,11 @@ describe('cart-dropdown component', () => {
|
|||
describe('getDisplayed', () => {
|
||||
test('returns "Verifying coverage" when not no comp, not itac, and deductible null', () => {
|
||||
// Arrange
|
||||
const storeData = {
|
||||
order: {
|
||||
payment: {
|
||||
insuranceCoverage: {
|
||||
coverageStatus: coverageStatuses.VERIFIED
|
||||
}
|
||||
},
|
||||
policy: {
|
||||
isITAC: false
|
||||
},
|
||||
currentDeductible: null
|
||||
}
|
||||
};
|
||||
const storeData = getDefaultState();
|
||||
storeData.order.payment.insuranceCoverage.coverageStatus = coverageStatuses.VERIFIED;
|
||||
storeData.order.policy.isITAC = false;
|
||||
storeData.order.currentDeductible = null;
|
||||
|
||||
const { wrapper } = getMountedComponent(storeData);
|
||||
const amount = 123;
|
||||
|
||||
|
|
@ -1021,19 +1199,11 @@ describe('cart-dropdown component', () => {
|
|||
});
|
||||
test('returns "Verifying coverage" when not no comp, not itac, and coverage status PENDING', () => {
|
||||
// Arrange
|
||||
const storeData = {
|
||||
order: {
|
||||
payment: {
|
||||
insuranceCoverage: {
|
||||
coverageStatus: coverageStatuses.PENDING
|
||||
}
|
||||
},
|
||||
policy: {
|
||||
isITAC: false
|
||||
},
|
||||
currentDeductible: 321
|
||||
}
|
||||
};
|
||||
const storeData = getDefaultState();
|
||||
storeData.order.payment.insuranceCoverage.coverageStatus = coverageStatuses.PENDING;
|
||||
storeData.order.policy.isITAC = false;
|
||||
storeData.order.currentDeductible = 321;
|
||||
|
||||
const { wrapper } = getMountedComponent(storeData);
|
||||
const amount = 123;
|
||||
|
||||
|
|
|
|||
|
|
@ -173,20 +173,7 @@ export default {
|
|||
availableVaps: Array
|
||||
},
|
||||
data() {
|
||||
const { currentDeductible } = useMainStore().order;
|
||||
const { glassToReplace, isRepair } = useMainStore().damage;
|
||||
const { supportingItems, glassParts, otherParts, vaps } = useMainStore().lineItems;
|
||||
|
||||
return {
|
||||
isRepair,
|
||||
glassToReplace: glassToReplace ?? [],
|
||||
vapsInOrder: vaps ?? [],
|
||||
baseServiceLineItems: [
|
||||
...(supportingItems ?? []),
|
||||
...(glassParts ?? []),
|
||||
...(otherParts ?? [])
|
||||
],
|
||||
deductible: currentDeductible,
|
||||
isExpanded: false,
|
||||
widget: {
|
||||
amountDue: 'AmountDueTextWidget',
|
||||
|
|
@ -202,9 +189,20 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
deductible() {
|
||||
// Note: added as computed so it can be used in the template.
|
||||
return useMainStore().order.currentDeductible;
|
||||
},
|
||||
showDeductibleCartItem() {
|
||||
return !useMainStore().isNoComp && !useMainStore().policy.isITAC;
|
||||
},
|
||||
baseServiceLineItems() {
|
||||
return [
|
||||
...(useMainStore().lineItems.supportingItems ?? []),
|
||||
...(useMainStore().lineItems.glassParts ?? []),
|
||||
...(useMainStore().lineItems.otherParts ?? [])
|
||||
];
|
||||
},
|
||||
baseServicePrice() {
|
||||
return getPriceOfLineItems(this.baseServiceLineItems);
|
||||
},
|
||||
|
|
@ -219,7 +217,26 @@ export default {
|
|||
return basePrice + this.packagePrice;
|
||||
},
|
||||
salesTax() {
|
||||
return 0; // TODO
|
||||
function sumTax(lineItems) {
|
||||
return lineItems?.reduce((accumulator, lineItem) => accumulator + (lineItem.salesTax ?? 0), 0) ?? 0;
|
||||
}
|
||||
|
||||
let result = 0;
|
||||
|
||||
if (useMainStore().payment.insuranceCoverage.isVerified
|
||||
&& (useMainStore().isITAC || useMainStore().isNoComp)) {
|
||||
result += sumTax(this.baseServiceLineItems);
|
||||
} else {
|
||||
// deductible or non-verified still need to show tax for Recycle Fee or Mobile Fee
|
||||
const recycleFeeLineItem = useMainStore().lineItems.supportingItems
|
||||
?.find((lineItem) => lineItem.partNumber === partNumberStrings.RECYCLE_FEE);
|
||||
|
||||
result += recycleFeeLineItem != null ? recycleFeeLineItem.salesTax : 0;
|
||||
}
|
||||
|
||||
result += sumTax(useMainStore().lineItems.vaps ?? []);
|
||||
|
||||
return result;
|
||||
},
|
||||
amountDue() {
|
||||
return this.showAsPaid
|
||||
|
|
@ -236,17 +253,17 @@ export default {
|
|||
},
|
||||
servicePackageTier() {
|
||||
return getHighestFullySatisfiedTier(
|
||||
this.glassToReplace,
|
||||
useMainStore().damage.glassToReplace ?? [],
|
||||
this.availableLineItems,
|
||||
this.isRepair,
|
||||
this.vapsInOrder
|
||||
useMainStore().damage.isRepair,
|
||||
useMainStore().lineItems.vaps ?? []
|
||||
);
|
||||
},
|
||||
servicePackageCartItems() {
|
||||
const packageContentTypes = getPackageContents(
|
||||
this.glassToReplace,
|
||||
useMainStore().damage.glassToReplace ?? [],
|
||||
this.availableLineItems,
|
||||
this.isRepair,
|
||||
useMainStore().damage.isRepair,
|
||||
this.servicePackageTier
|
||||
) ?? [];
|
||||
const items = [];
|
||||
|
|
@ -271,7 +288,7 @@ export default {
|
|||
return this.getCartItemForVapsPart(partTypeStrings.RAIN_DEFENSE);
|
||||
},
|
||||
packagePrice() {
|
||||
return getPriceOfLineItems(this.vapsInOrder);
|
||||
return getPriceOfLineItems(useMainStore().lineItems.vaps ?? []);
|
||||
},
|
||||
amountDueLabel() {
|
||||
return this.getCmsContent(this.widget.amountDue, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
|
|
@ -355,7 +372,7 @@ export default {
|
|||
},
|
||||
getCartItemForVapsPart(partType) {
|
||||
const label = this.getCmsContentForVapsType(partType);
|
||||
const lineItems = this.vapsInOrder
|
||||
const lineItems = useMainStore().lineItems.vaps
|
||||
?.filter((vapsLineItem) => vapsLineItem.partType === partType);
|
||||
return this.getCartItem(label, lineItems);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -115,6 +115,8 @@ export default {
|
|||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
await useMainStore().setPriceAndSalesTaxForOrderLineItems();
|
||||
|
||||
const unpricedVaps = [...resultMap.wipers, resultMap.rainDefense];
|
||||
|
||||
let hasBailedOut = false;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ function getTimeSlotsAdditionalEventData(
|
|||
return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ProvisionalTriggers:${provisionalTriggers.join(',')}`;
|
||||
}
|
||||
|
||||
const getDefaultState = () => ({
|
||||
export const getDefaultState = () => ({
|
||||
order: {
|
||||
vehicle: {
|
||||
policyVehicleId: null,
|
||||
|
|
@ -1556,11 +1556,28 @@ export const useMainStore = defineStore({
|
|||
this.order.lineItems.mobileFee = mobileFee;
|
||||
},
|
||||
|
||||
async setPriceAndSalesTaxForOrderLineItems() {
|
||||
const lineItemsToTax = [
|
||||
...(this.order.lineItems.supportingItems ?? []),
|
||||
...(this.order.lineItems.glassParts ?? []),
|
||||
...(this.order.lineItems.otherParts ?? []),
|
||||
...(this.order.lineItems.vaps ?? [])
|
||||
];
|
||||
|
||||
if (this.order.lineItems.mobileFee != null) {
|
||||
lineItemsToTax.push(this.order.lineItems.mobileFee);
|
||||
}
|
||||
|
||||
const pricedLineItemsToTax = await this.getPriceOrderItems(lineItemsToTax);
|
||||
|
||||
this.taxOrderItemsAndSaveServerData(pricedLineItemsToTax);
|
||||
},
|
||||
|
||||
updateVehicle(vehicle) {
|
||||
// Assuming that the method caller pass all the properties.
|
||||
// otherwise need to check for undefined for every property.
|
||||
this.vehicle.policyVehicleId = vehicle.policyVehicleId;
|
||||
this.vehicle.carId = vehicle.carId;
|
||||
this.order.vehicle.policyVehicleId = vehicle.policyVehicleId;
|
||||
this.order.vehicle.carId = vehicle.carId;
|
||||
this.order.vehicle.category = vehicle.category;
|
||||
this.order.vehicle.year = vehicle.year;
|
||||
this.order.vehicle.make = vehicle.make;
|
||||
|
|
|
|||
Loading…
Reference in a new issue