From 7ff4edd7434445b592cddc53c91b7bf80c932a64 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 23 Aug 2024 13:14:48 -0400 Subject: [PATCH 1/3] Fixing itac endpoint problem --- src/helpers/line-items-helper.spec.js | 51 +++++++++++++++++++ .../cart-dropdown/cart-dropdown.vue | 4 +- .../coverage-statement/coverage-statement.vue | 1 + src/mixins/vehicle-questions-mixin.js | 11 ++-- src/store/index.js | 36 +++++++++++-- 5 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src/helpers/line-items-helper.spec.js b/src/helpers/line-items-helper.spec.js index af8337a7..c191d852 100644 --- a/src/helpers/line-items-helper.spec.js +++ b/src/helpers/line-items-helper.spec.js @@ -1,6 +1,57 @@ import { getLineItemsFlattened } from '@/helpers/line-items-helper'; describe('getLineItemsFlattened', () => { + function mapLineItemsForGetITACPrice(lineItems) { + console.log(`before: ${JSON.stringify(lineItems)}`); + const x = lineItems.map(({ safelitePartNumber, childParts, ...rest }) => ({ + ...rest, + partNumber: safelitePartNumber, + childParts: childParts.map((part) => ({ + partNumber: part.safelitePartNumber + })) + })); + console.log(`after: ${JSON.stringify(x)}`); + return x; + } + describe.only('test', () => { + // Arrange + const lineItems = [{ + apple: 'a', + banana: 'b', + partNumber: 111, + safelitePartNumber: 222, + childParts: [ + { + partNumber: 333, + safelitePartNumber: 444 + }, + { + partNumber: 555, + safelitePartNumber: 666 + } + ] + }]; + const expected = [{ + apple: 'a', + banana: 'b', + partNumber: 222, + childParts: [ + { + partNumber: 444 + }, + { + partNumber: 666 + } + ] + }]; + + // Act + const result = mapLineItemsForGetITACPrice(lineItems); + console.log(JSON.stringify(result)); + + // Assert + expect(result).toMatchObject(expected); + }); describe('getLineItemsFlattened', () => { it('Returns empty array when null is passed', () => { // Arrange diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index ebb083fa..40993b6d 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -178,7 +178,7 @@ import { import { getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator'; const VERIFYING_COVERAGE = 'Verifying coverage'; -const RECYCLING_MODAL_REF_NAME = "RecycleModal"; +const RECYCLING_MODAL_REF_NAME = 'RecycleModal'; export default { name: 'cart-dropdown', @@ -234,6 +234,8 @@ export default { return getRecycleFeeLineItem(this.cartOrder); }, servicePrice() { + const x = getServiceLineItems(this.cartOrder); + console.log(`service line items: ${JSON.stringify(x)}`); return getPriceOfLineItems(getServiceLineItems(this.cartOrder)) ?? 0; }, isUnverified() { diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 41f6d3b8..979ca436 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -382,6 +382,7 @@ export default { ...(this.mainStore.lineItems.supportingItems ?? []), ...(clonedGlassParts ?? []) ]; + console.log(`available line items: ${JSON.stringify(availableLineItems)}`); // We only call the ITAC pricing endpoint if we are not repair or we are NoComp if (!this.isRepair || this.mainStore.isNoComp) { diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 76964e08..c5f59540 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -23,9 +23,10 @@ export default { glassParts.forEach((glass) => { if (Array.isArray(glass.parts) && glass.parts.length === 1) { const singlePart = glass.parts[0]; - if (singlePart){ + if (singlePart) { reducedGlassParts.push({ partNumber: singlePart.partNumber, + safelitePartNumber: singlePart.safelitePartNumber, description: singlePart.description, color: singlePart.color, partType: singlePart.partType, @@ -119,10 +120,10 @@ export default { }); // remove any disabled dependent answers - const answerQuestionNums = new Set(alreadyAnsweredQuestions[alreadyAnsweredQuestions.length-1].answeredQuestions.map(q => q.questionNum)); - glass.questions.forEach(q => { - if(!answerQuestionNums.has(q.questionSequence)) { - delete q.answerSelected + const answerQuestionNums = new Set(alreadyAnsweredQuestions[alreadyAnsweredQuestions.length - 1].answeredQuestions.map((q) => q.questionNum)); + glass.questions.forEach((q) => { + if (!answerQuestionNums.has(q.questionSequence)) { + delete q.answerSelected; } }); diff --git a/src/store/index.js b/src/store/index.js index 7f26d157..8df3849f 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1076,9 +1076,23 @@ export const useMainStore = defineStore({ return availableLineItems; }, + // TODO move to helper + // replaces partNumber, which is NAGS with the safelite part number + mapLineItemsForGetITACPrice(lineItems) { + const x = lineItems.map(({ safelitePartNumber, childParts, ...rest }) => ({ + ...rest, + partNumber: safelitePartNumber, + childParts: childParts.map((part) => ({ + partNumber: part.safelitePartNumber + })) + })); + return x; + }, + + // NOTE: The endpoint requires that safelite part numbers be used!! async getITACPriceOrderItems(availableLineItems) { const { policy, vehicle, contactInfo, serviceLocation, insuranceCoverage } = this.order; - + const lineItemsUsingSafelitePartNumber = this.mapLineItemsForGetITACPrice(availableLineItems); const response = await globalMethods .callHttpClient({ method: endpoints.GetITACPriceOrderItems.method, @@ -1088,7 +1102,7 @@ export const useMainStore = defineStore({ ReferralNumber: this.order.referralNumber, ReferralSequenceNumber: this.order.referralSequenceNumber, ReferralDate: `${this.order.referralDate}Z`, - lineItems: getLineItemsFlattened(availableLineItems), + lineItems: getLineItemsFlattened(lineItemsUsingSafelitePartNumber), ServerData: this.order.lineItems.serverData, ServiceZipCode: serviceLocation.zipCode, Customer: { @@ -1122,6 +1136,8 @@ export const useMainStore = defineStore({ const { lineItems, serverData, isItac, primaryBillToNumber } = response.data; + console.log(`response data: ${JSON.stringify(response.data)}`); + if (serverData) { this.order.lineItems.serverData = serverData; } @@ -1141,7 +1157,9 @@ export const useMainStore = defineStore({ } if (lineItems) { - const retAvailableLineItems = addPricesToLineItems(availableLineItems, lineItems); + console.log(`returned line items: ${JSON.stringify(lineItems)}`); + const retAvailableLineItems = addPricesToLineItems(availableLineItems, lineItems, false); + console.log(`line items with prices: ${JSON.stringify(retAvailableLineItems)}`); return retAvailableLineItems; } @@ -2767,14 +2785,22 @@ function convertGlassPieceNamingFromApi(glassArray) { return glassArray; } -function addPricesToLineItems(lineItems, pricingLineItems) { +// TODO does this work +// Note this is used for both the insurance and the itac endpoints, so it needs to deal with safelite or nags part numbers +function addPricesToLineItems(lineItems, pricingLineItems, pricedPartNumberIsNags = true) { const partOffset = {}; + const partNumberProperty = pricedPartNumberIsNags ? 'partNumber' : 'safelitePartNumber'; + + console.log(partNumberProperty); + console.log(lineItems[0].partNumber); + console.log(lineItems[0].safelitePartNumber); + console.log(lineItems[0][partNumberProperty]); lineItems.forEach((lineItem) => { if (lineItem.childParts) { addPricesToLineItems(lineItem.childParts, pricingLineItems); } - const pricedIndex = findLineItemIndex(pricingLineItems, lineItem.partNumber, partOffset[lineItem.partNumber] ?? 0); + const pricedIndex = findLineItemIndex(pricingLineItems, lineItem[partNumberProperty], partOffset[lineItem.partNumber] ?? 0); if (pricedIndex !== -1) { const pricedLineItem = pricingLineItems[pricedIndex]; lineItem.laborAmount = pricedLineItem.laborAmount; From 328aec39bd737edc0b4f303ebef11b7dfda71744 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 23 Aug 2024 13:23:11 -0400 Subject: [PATCH 2/3] clean up round 1 --- .../cart-dropdown/cart-dropdown.vue | 2 -- .../coverage-statement/coverage-statement.vue | 1 - src/store/index.js | 16 ++++------------ 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 40993b6d..34788563 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -234,8 +234,6 @@ export default { return getRecycleFeeLineItem(this.cartOrder); }, servicePrice() { - const x = getServiceLineItems(this.cartOrder); - console.log(`service line items: ${JSON.stringify(x)}`); return getPriceOfLineItems(getServiceLineItems(this.cartOrder)) ?? 0; }, isUnverified() { diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 979ca436..41f6d3b8 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -382,7 +382,6 @@ export default { ...(this.mainStore.lineItems.supportingItems ?? []), ...(clonedGlassParts ?? []) ]; - console.log(`available line items: ${JSON.stringify(availableLineItems)}`); // We only call the ITAC pricing endpoint if we are not repair or we are NoComp if (!this.isRepair || this.mainStore.isNoComp) { diff --git a/src/store/index.js b/src/store/index.js index 8df3849f..5036825a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1136,8 +1136,6 @@ export const useMainStore = defineStore({ const { lineItems, serverData, isItac, primaryBillToNumber } = response.data; - console.log(`response data: ${JSON.stringify(response.data)}`); - if (serverData) { this.order.lineItems.serverData = serverData; } @@ -1157,9 +1155,7 @@ export const useMainStore = defineStore({ } if (lineItems) { - console.log(`returned line items: ${JSON.stringify(lineItems)}`); const retAvailableLineItems = addPricesToLineItems(availableLineItems, lineItems, false); - console.log(`line items with prices: ${JSON.stringify(retAvailableLineItems)}`); return retAvailableLineItems; } @@ -2785,28 +2781,24 @@ function convertGlassPieceNamingFromApi(glassArray) { return glassArray; } -// TODO does this work // Note this is used for both the insurance and the itac endpoints, so it needs to deal with safelite or nags part numbers function addPricesToLineItems(lineItems, pricingLineItems, pricedPartNumberIsNags = true) { const partOffset = {}; - const partNumberProperty = pricedPartNumberIsNags ? 'partNumber' : 'safelitePartNumber'; + const partNumberPropertyToCompare = pricedPartNumberIsNags ? 'partNumber' : 'safelitePartNumber'; - console.log(partNumberProperty); - console.log(lineItems[0].partNumber); - console.log(lineItems[0].safelitePartNumber); - console.log(lineItems[0][partNumberProperty]); lineItems.forEach((lineItem) => { if (lineItem.childParts) { addPricesToLineItems(lineItem.childParts, pricingLineItems); } + const partNumberToCompare = lineItem[partNumberPropertyToCompare]; - const pricedIndex = findLineItemIndex(pricingLineItems, lineItem[partNumberProperty], partOffset[lineItem.partNumber] ?? 0); + const pricedIndex = findLineItemIndex(pricingLineItems, partNumberToCompare, partOffset[partNumberToCompare] ?? 0); if (pricedIndex !== -1) { const pricedLineItem = pricingLineItems[pricedIndex]; lineItem.laborAmount = pricedLineItem.laborAmount; lineItem.sellingPrice = pricedLineItem.sellingPrice; lineItem.kitPrice = pricedLineItem.kitPrice; - partOffset[lineItem.partNumber] = pricedIndex + 1; + partOffset[partNumberToCompare] = pricedIndex + 1; } }); return lineItems; From c18b6bf8b94bfeadbea2abc0e323da662d83d68f Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 23 Aug 2024 13:41:08 -0400 Subject: [PATCH 3/3] adding tests --- src/helpers/line-items-helper.js | 11 +++ src/helpers/line-items-helper.spec.js | 119 +++++++++++++++++--------- src/store/index.js | 17 +--- 3 files changed, 91 insertions(+), 56 deletions(-) diff --git a/src/helpers/line-items-helper.js b/src/helpers/line-items-helper.js index 9ad4bca3..e5c02530 100644 --- a/src/helpers/line-items-helper.js +++ b/src/helpers/line-items-helper.js @@ -6,3 +6,14 @@ export function getLineItemsFlattened(lineItems) { export function findLineItemIndex(lineItems, partNumber, startIndex = 0) { return lineItems.findIndex((li, index) => index >= startIndex && li.partNumber === partNumber); } + +// replaces partNumber, which is initially NAGS format, with the safelite part number +export function mapSafelitePartNumberToPartNumber(lineItems) { + return lineItems?.map(({ safelitePartNumber, childParts, ...rest }) => ({ + ...rest, + partNumber: safelitePartNumber, + childParts: childParts?.map((part) => ({ + partNumber: part.safelitePartNumber + })) ?? [] + })) ?? []; +} diff --git a/src/helpers/line-items-helper.spec.js b/src/helpers/line-items-helper.spec.js index c191d852..6b756cdf 100644 --- a/src/helpers/line-items-helper.spec.js +++ b/src/helpers/line-items-helper.spec.js @@ -1,56 +1,93 @@ -import { getLineItemsFlattened } from '@/helpers/line-items-helper'; +import { getLineItemsFlattened, mapSafelitePartNumberToPartNumber } from '@/helpers/line-items-helper'; describe('getLineItemsFlattened', () => { - function mapLineItemsForGetITACPrice(lineItems) { - console.log(`before: ${JSON.stringify(lineItems)}`); - const x = lineItems.map(({ safelitePartNumber, childParts, ...rest }) => ({ - ...rest, - partNumber: safelitePartNumber, - childParts: childParts.map((part) => ({ - partNumber: part.safelitePartNumber - })) - })); - console.log(`after: ${JSON.stringify(x)}`); - return x; - } - describe.only('test', () => { - // Arrange - const lineItems = [{ - apple: 'a', - banana: 'b', - partNumber: 111, - safelitePartNumber: 222, - childParts: [ + describe('mapSafelitePartNumberToPartNumber', () => { + test.each([null, undefined, []])('returns empty list when %p passed', (lineItems) => { + // Arrange + const expected = []; + + // Act + const result = mapSafelitePartNumberToPartNumber(lineItems); + + // Assert + expect(result).toMatchObject(expected); + }); + test('assigns partNumber to null when safelitePartNumber DNE', () => { + // Arrange + const lineItems = [ { - partNumber: 333, - safelitePartNumber: 444 + apple: 'a', + partNumber: 111 + } + ]; + const expected = [ + { + apple: 'a', + partNumber: undefined, + childParts: [] + } + ]; + + // Act + const result = mapSafelitePartNumberToPartNumber(lineItems); + + // Assert + expect(result).toMatchObject(expected); + }); + test('assigns partNumber as expected when multiple line items passed', () => { + // Arrange + const lineItems = [ + { + apple: 'a', + banana: 'b', + partNumber: 111, + safelitePartNumber: 222, + childParts: [ + { + partNumber: 333, + safelitePartNumber: 444 + }, + { + partNumber: 555, + safelitePartNumber: 666 + } + ] }, { - partNumber: 555, - safelitePartNumber: 666 + apple: 'apple', + banana: 'banana', + partNumber: 123, + safelitePartNumber: 321 } - ] - }]; - const expected = [{ - apple: 'a', - banana: 'b', - partNumber: 222, - childParts: [ + ]; + const expected = [ { - partNumber: 444 + apple: 'a', + banana: 'b', + partNumber: 222, + childParts: [ + { + partNumber: 444 + }, + { + partNumber: 666 + } + ] }, { - partNumber: 666 + apple: 'apple', + banana: 'banana', + partNumber: 321, + childParts: [] } - ] - }]; + ]; - // Act - const result = mapLineItemsForGetITACPrice(lineItems); - console.log(JSON.stringify(result)); + // Act + const result = mapSafelitePartNumberToPartNumber(lineItems); - // Assert - expect(result).toMatchObject(expected); + // Assert + expect(result).toMatchObject(expected); + }); }); describe('getLineItemsFlattened', () => { it('Returns empty array when null is passed', () => { diff --git a/src/store/index.js b/src/store/index.js index 5036825a..c165d552 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -24,7 +24,7 @@ import partTypeStrings from '@/constants/part-type-strings'; import bailoutMessage from '@/constants/bailoutMessage'; import bailoutCode from '@/constants/bailoutCode'; import partNumberStrings from '@/constants/part-number-strings'; -import { findLineItemIndex, getLineItemsFlattened } from '@/helpers/line-items-helper'; +import { findLineItemIndex, getLineItemsFlattened, mapSafelitePartNumberToPartNumber } from '@/helpers/line-items-helper'; import { buildQueryStringParameterFromArrayOfComplexObjects, getLineItemQueryString, getTaxLineItemQueryString } from '@/helpers/querystring-helper'; import coverageType from '@/constants/coverage-type'; import { getExperimentSettingValue, getFeatureTogglesQueryString } from '@/helpers/experiment-helper'; @@ -1076,23 +1076,10 @@ export const useMainStore = defineStore({ return availableLineItems; }, - // TODO move to helper - // replaces partNumber, which is NAGS with the safelite part number - mapLineItemsForGetITACPrice(lineItems) { - const x = lineItems.map(({ safelitePartNumber, childParts, ...rest }) => ({ - ...rest, - partNumber: safelitePartNumber, - childParts: childParts.map((part) => ({ - partNumber: part.safelitePartNumber - })) - })); - return x; - }, - // NOTE: The endpoint requires that safelite part numbers be used!! async getITACPriceOrderItems(availableLineItems) { const { policy, vehicle, contactInfo, serviceLocation, insuranceCoverage } = this.order; - const lineItemsUsingSafelitePartNumber = this.mapLineItemsForGetITACPrice(availableLineItems); + const lineItemsUsingSafelitePartNumber = mapSafelitePartNumberToPartNumber(availableLineItems); const response = await globalMethods .callHttpClient({ method: endpoints.GetITACPriceOrderItems.method,