From 3bd15f9054803c9afc009fe8a63fb38e5982c5dc Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Tue, 17 Mar 2026 09:31:58 -0400 Subject: [PATCH 1/5] INSR-7995: Adyen integration --- package-lock.json | 41 ++ package.json | 1 + src/constants/application-config.js | 4 +- src/constants/endpoints.js | 9 + src/constants/experiments.js | 6 +- src/constants/progress-bar-mapper.js | 4 + src/helpers/adyen-helper.js | 171 +++++ src/layouts/payment-method/payment-method.vue | 23 +- .../payment-page-adyen/payment-page-adyen.vue | 653 ++++++++++++++++++ .../payment-return-adyen.vue | 182 +++++ src/router/router-constants/issPage-values.js | 2 + .../router-constants/navigation-scenarios.js | 2 + src/router/router-constants/routing-table.js | 38 + src/store/index.js | 30 + vue.config.js | 2 + 15 files changed, 1163 insertions(+), 5 deletions(-) create mode 100644 src/helpers/adyen-helper.js create mode 100644 src/layouts/payment-page-adyen/payment-page-adyen.vue create mode 100644 src/layouts/payment-return-adyen/payment-return-adyen.vue diff --git a/package-lock.json b/package-lock.json index c2c89abc..c8ac4360 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "digitalconsumer.iss", "version": "0.1.0", "dependencies": { + "@adyen/adyen-web": "^6.31.1", "axios": "^1.13.5", "axios-retry": "^3.5.0", "bootstrap": "^5.3", @@ -93,6 +94,18 @@ "dev": true, "license": "MIT" }, + "node_modules/@adyen/adyen-web": { + "version": "6.31.1", + "resolved": "https://registry.npmjs.org/@adyen/adyen-web/-/adyen-web-6.31.1.tgz", + "integrity": "sha512-vxeJW1bTvjXxYf6CkPQV8gbYIhm/hupcjjeoKkkBdxk7geW3qy18Jlco4/MuSeb88ctTRM3gebwFXpqF2NjBLQ==", + "license": "MIT", + "dependencies": { + "@types/applepayjs": "14.0.9", + "@types/googlepay": "0.7.10", + "classnames": "2.5.1", + "preact": "10.28.2" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "dev": true, @@ -4125,6 +4138,12 @@ "node": ">= 10" } }, + "node_modules/@types/applepayjs": { + "version": "14.0.9", + "resolved": "https://registry.npmjs.org/@types/applepayjs/-/applepayjs-14.0.9.tgz", + "integrity": "sha512-xEprYbb0TEP/XIiDPbVnTYpDai8fTFpsQfVSfTd81Is2GOMUy7ie019eyX6Mz2ECxfjoUVKaiGSL577roIeHCg==", + "license": "MIT" + }, "node_modules/@types/aria-query": { "version": "5.0.1", "dev": true, @@ -4283,6 +4302,12 @@ "@types/node": "*" } }, + "node_modules/@types/googlepay": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@types/googlepay/-/googlepay-0.7.10.tgz", + "integrity": "sha512-ByXjDfxEp87zsjw5cVsNKEeA+AIJYcWwJvRqPu85jO0Lp/FeG67csnf4mqbPaIxmdI6+Khp3v5I0yyjq9MrGhw==", + "license": "MIT" + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "dev": true, @@ -7371,6 +7396,12 @@ "dev": true, "license": "MIT" }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/clean-css": { "version": "5.3.1", "dev": true, @@ -17407,6 +17438,16 @@ "dev": true, "license": "MIT" }, + "node_modules/preact": { + "version": "10.28.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.2.tgz", + "integrity": "sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "dev": true, diff --git a/package.json b/package.json index 32e0fad3..c60c9e10 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "lint:inspect": "eslint --inspect-config" }, "dependencies": { + "@adyen/adyen-web": "^6.31.1", "axios": "^1.13.5", "axios-retry": "^3.5.0", "bootstrap": "^5.3", diff --git a/src/constants/application-config.js b/src/constants/application-config.js index 1e5ee6d8..c8231ecb 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -26,7 +26,9 @@ const applicationConfig = Object.freeze({ FRONTEND_LOGGER_PATH: "/analytics/api/v1/logging", BAILOUT_ON_APPLICATION_ERROR: true, BAILOUT_ON_API_ERROR: true, - BAILOUT_ON_ROUTER_ERROR: true + BAILOUT_ON_ROUTER_ERROR: true, + ADYEN_CLIENT_KEY: process.env.VUE_APP_ADYEN_CLIENT_KEY, + ADYEN_ENVIRONMENT: process.env.VUE_APP_ADYEN_ENVIRONMENT }); export default applicationConfig; diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 057ef9e4..e322bb48 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -10,6 +10,7 @@ const PARTS_BASE_URL = '/parts/api/v1/parts'; const PRICE_BASE_URL = '/price/api/v1/price'; const SCHEDULE_BASE_URL = '/schedule/api/v1/schedule'; const VEHICLE_BASE_URL = '/vehicle/api/v1/vehicle'; +const PAYMENT_BASE_URL = '/payment/api/v1/payment'; const endpoints = Object.freeze({ GetRouteInfo: { @@ -239,6 +240,14 @@ const endpoints = Object.freeze({ GetPaymentSignature: { url: `${ORDER_BASE_URL}/sign`, method: 'POST' + }, + InitializeAdyenPayment: { + url: `${PAYMENT_BASE_URL}/payment/session/initialize-session`, + method: "POST", + }, + GetAdyenSessionResult: { + url: `${PAYMENT_BASE_URL}/payment/session/session-result`, + method: "POST", } }); diff --git a/src/constants/experiments.js b/src/constants/experiments.js index f1d52ede..9e959331 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -1,7 +1,8 @@ const experimentUniverses = Object.freeze({ ISS_FUNNEL: 'ISSFunnel', ISS_FEATURETOGGLE_AREFEES_HIDDEN: 'NextGenISS_FeatureToggle_AreFeesHidden', - ISS_FEATURETOGGLE_AREFEES_OVERRIDDEN: 'NextGenISS_FeatureToggle_AreFeesOverridden' + ISS_FEATURETOGGLE_AREFEES_OVERRIDDEN: 'NextGenISS_FeatureToggle_AreFeesOverridden', + ADYEN_PAYMENT_TEST: 'NextGenAdyenPaymentTest' }); const experimentSettings = Object.freeze({ @@ -10,7 +11,8 @@ const experimentSettings = Object.freeze({ ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN: 'HideMobileFee', ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_OVERRIDDEN: 'OverrideMobileFee', ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_HIDDEN: 'HideRecycleFee', - ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_OVERRIDDEN: 'OverrideRecycleFee' + ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_OVERRIDDEN: 'OverrideRecycleFee', + ISS_ENABLE_ADYEN_V1: 'ISS_Enable_Adyen_V1' }); const experimentTriggers = Object.freeze({ diff --git a/src/constants/progress-bar-mapper.js b/src/constants/progress-bar-mapper.js index c47c738a..935c3b38 100644 --- a/src/constants/progress-bar-mapper.js +++ b/src/constants/progress-bar-mapper.js @@ -66,6 +66,10 @@ export const pageProgressMapper = { // No progress bar on this page percent: 0 }, + 'payment-adyen': { + // No progress bar on this page + percent: 0 + }, 'tpa-search': { percent: 80 }, diff --git a/src/helpers/adyen-helper.js b/src/helpers/adyen-helper.js new file mode 100644 index 00000000..1cc719d2 --- /dev/null +++ b/src/helpers/adyen-helper.js @@ -0,0 +1,171 @@ +import { AdyenCheckout } from "@adyen/adyen-web/auto"; +import { useMainStore } from "@/store"; +import globalMethods from "@/global-methods"; +import endpoints from "@/constants/endpoints"; +import { AppointmentTypeStrings } from "@/constants/schedule-constants"; +import { paymentMethods } from "@/constants/payment-method-constants"; +import applicationConfig from "@/constants/application-config"; + +export async function getNewSession(sessionConfig) {} + +export async function getSessionInfo(sessionId, encryptedSessionResult, pageNameToLog = "") { + const order = useMainStore().order; + const location = getLocationInfo(order); + const workOrder = getWorkOrderLastSixDigits(order); + const system = getSourceSystem(); + + const request = { + sessionId: sessionId, + sessionResult: encryptedSessionResult, + zipCodeCtu: location.zipCodeCtu, + workOrderNumber: workOrder, + sourceSystem: system, + }; + + const response = await globalMethods.callHttpClient({ + method: endpoints.GetAdyenSessionResult.method, + endpoint: endpoints.GetAdyenSessionResult.url, + payload: request, + logApiCall: true, + pageNameToLog: pageNameToLog, + }); + + return response?.data; +} + +export async function createAdyenCheckout({ + session: { id, sessionData }, + handlers: { onPaymentCompleted, onPaymentFailed, onError }, + options: { showPayButton = true, amount }, +}) { + const config = { + session: { + id: id, + sessionData: sessionData, + }, + clientKey: applicationConfig.ADYEN_CLIENT_KEY, + environment: applicationConfig.ADYEN_ENVIRONMENT, + locale: "en_US", + countryCode: "US", + showPayButton: showPayButton, + translations: { + en_US: { + "creditCard.securityCode.label": "CVV/CVC", + }, + }, + onPaymentCompleted: onPaymentCompleted, + onPaymentFailed: onPaymentFailed, + onError: onError, + }; + + if (amount !== undefined && amount !== null) { + config.amount = { + value: amount, + currency: "USD", + }; + } + + console.log(`Creating checkout with configuration:`); + console.log(config); + + return await AdyenCheckout(config); +} + +export function mapAdyenToIssPaymentMethod(adyenMethod) { + const paymentMethodMap = { + ["scheme"]: paymentMethods.CREDIT_CARD, + ["afterpaytouch_US"]: paymentMethods.AFTERPAY, + ["paypal"]: paymentMethods.PAYPAL, + ["applepay"]: paymentMethods.APPLEPAY, + }; + + const match = paymentMethodMap[adyenMethod]; + + return match ?? paymentMethods.CREDIT_CARD; +} + +export function mapIssToAdyenPaymentMethod(issMethod) { + const paymentMethodMap = { + [paymentMethods.CREDIT_CARD]: "scheme", + [paymentMethods.AFTERPAY]: "afterpaytouch_US", + [paymentMethods.PAYPAL]: "paypal", + [paymentMethods.APPLEPAY]: "applepay", + [paymentMethods.PayNow]: null, + [paymentMethods.PAY_AT_TIME_OF_SERVICE]: null, + }; + + const match = paymentMethodMap[issMethod]; + + return match; +} + +export function generateCcToken(adyenSessionInfo) { + const order = useMainStore().order; + const locationInfo = getLocationInfo(order); + console.log("Generating CC Token with the following Adyen Session Info:"); + console.log(JSON.parse(JSON.stringify(adyenSessionInfo))); + + const ccToken = { + subscriptionId: adyenSessionInfo?.storedToken, + expMonth: adyenSessionInfo?.cardExpiryMonth, + expYear: adyenSessionInfo?.cardExpiryYear, + cardType: adyenSessionInfo?.cardType, + billToPostalCode: locationInfo.zipCode, // TODO - real data? + billToFirstName: order.customer.firstName, // TODO - real data? + billToLastName: order.customer.lastName, // TODO - real data? + referenceNumber: adyenSessionInfo?.workOrderNumber, + authCode: adyenSessionInfo?.authCode, + transactionId: adyenSessionInfo?.transactionReference, + transReferenceNumber: adyenSessionInfo?.transactionReference, + lastFour: adyenSessionInfo?.last4DigitsOfCard, + }; + + return ccToken; +} + +function getLocationInfo(order) { + const serviceLocation = order.serviceLocation; + const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE || + serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP; + if (isMobile) { + return { + address: serviceLocation.address, + address2: serviceLocation.address2, + city: serviceLocation.city, + state: serviceLocation.state, + zipCode: serviceLocation.zipCode, + zipCodeCtu: serviceLocation.zipCodeCtu, + }; + } else { + const providerInfo = serviceLocation.provider.address; + return { + address: providerInfo.streetAddress, + address2: "", + city: providerInfo.city, + state: providerInfo.state, + zipCode: providerInfo.zipCode, + zipCodeCtu: providerInfo.zipCodeCtu, + }; + } +} + +function getWorkOrderLastSixDigits(order) { + const workOrderNumber = order.workOrderNumber ?? ""; + const tokens = workOrderNumber.split("-"); + const lastSegment = tokens[tokens.length - 1] ?? ""; + const numDigits = lastSegment.length; + const numZeroes = 6 - numDigits; + + let result = ""; + for (let i = 0; i < numZeroes; i++) { + result += "0"; + } + + result += lastSegment; + + return result; +} + +function getSourceSystem() { + return "ISS-NextGen"; +} diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 41eee5ee..0c3d0c7d 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -239,8 +239,23 @@ export default { return !isEnabled || useMainStore().isUnverified || (useMainStore().isDeductible && isDeductibleTotalEqualToZero); }, + isAdyenEnabled() { + const adyenEnabled = this.getSettingValue(experimentSettings.ISS_ENABLE_ADYEN_V1); + return adyenEnabled === 'true'; + }, paymentMethodWidgetName() { - return supportsApplePay() ? this.widget.paymentMethodApplePay : this.widget.paymentMethod; + let showApplePay = false; + if (this.isAdyenEnabled) { + // Apple Pay is Available in Adyen if the protocol is HTTPS + if (window.location.protocol === 'https:') { + showApplePay = true; + } + } + else { + showApplePay = supportsApplePay(); + } + + return showApplePay ? this.widget.paymentMethodApplePay : this.widget.paymentMethod; }, showCartTotal() { return this.mainStore.isVerified && (this.mainStore.isITAC || this.mainStore.isNoComp @@ -418,8 +433,12 @@ export default { bailoutOnError: true }); + const scenario = this.isAdyenEnabled + ? this.navigationScenarios.CLICKED_PAY_NOW_ADYEN + : this.navigationScenarios.CLICKED_PAY_NOW; + this.$router.navigate( - this.navigationScenarios.CLICKED_PAY_NOW, + scenario, this.$route, {}, { [routerParams.SKIP_SAVE_SESSION]: true } diff --git a/src/layouts/payment-page-adyen/payment-page-adyen.vue b/src/layouts/payment-page-adyen/payment-page-adyen.vue new file mode 100644 index 00000000..afc42249 --- /dev/null +++ b/src/layouts/payment-page-adyen/payment-page-adyen.vue @@ -0,0 +1,653 @@ + + + diff --git a/src/layouts/payment-return-adyen/payment-return-adyen.vue b/src/layouts/payment-return-adyen/payment-return-adyen.vue new file mode 100644 index 00000000..b84bcb5c --- /dev/null +++ b/src/layouts/payment-return-adyen/payment-return-adyen.vue @@ -0,0 +1,182 @@ + + + diff --git a/src/router/router-constants/issPage-values.js b/src/router/router-constants/issPage-values.js index c683e971..4d36c097 100644 --- a/src/router/router-constants/issPage-values.js +++ b/src/router/router-constants/issPage-values.js @@ -19,6 +19,8 @@ const issPageValues = Object.freeze({ PAYMENT_METHOD: 'payment-method', PAYMENT_PAGE: 'payment-page', PAYMENT_RETURN: 'payment-return', + PAYMENT_PAGE_ADYEN: 'payment-page-adyen', + PAYMENT_RETURN_ADYEN: 'payment-return-adyen', PART_QUESTIONS: 'part-questions', POLICY_HOLDER_DETAILS: 'policy-holder-details', PROVIDER_PREFERENCE: 'provider-preference', diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 2c9768bf..b0b5bea9 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -102,6 +102,8 @@ const navigationScenarios = Object.freeze({ CLICKED_BACK_INSHOP: 'CLICKED_BACK_INSHOP', CLICKED_BACK_MOBILE: 'CLICKED_BACK_MOBILE', CLICKED_PAY_NOW: 'CLICKED_PAY_NOW', + CLICKED_PAY_NOW_ADYEN: 'CLICKED_PAY_NOW_ADYEN', + PAY_IN_ADVANCE_CANCEL: 'PAY_IN_ADVANCE_CANCEL', PAY_IN_ADVANCE_ERROR: 'PAY_IN_ADVANCE_ERROR', PAY_IN_ADVANCE_CREDIT_CARD_ERROR: 'PAY_IN_ADVANCE_CREDIT_CARD_ERROR', PAY_IN_ADVANCE_SUCCESS: 'PAY_IN_ADVANCE_SUCCESS', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index aa686acd..f461bf59 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -641,6 +641,10 @@ const routingTable = () => [ scenario: navigationScenarios.CLICKED_PAY_NOW, destinationIssPageValue: issPageValues.PAYMENT_PAGE }, + { + scenario: navigationScenarios.CLICKED_PAY_NOW_ADYEN, + destinationIssPageValue: issPageValues.PAYMENT_PAGE_ADYEN + }, { scenario: navigationScenarios.EDIT_SERVICE_LOCATION_INSHOP, destinationIssPageValue: issPageValues.SCHEDULE_PAGE @@ -676,6 +680,23 @@ const routingTable = () => [ } ] }, + { + issPageValue: issPageValues.PAYMENT_PAGE_ADYEN, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationIssPageValue: issPageValues.PAYMENT_METHOD + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationIssPageValue: issPageValues.ORDER_CONFIRMATION + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS, + destinationIssPageValue: issPageValues.ORDER_CONFIRMATION + } + ] + }, { issPageValue: issPageValues.PAYMENT_RETURN, maps: [ @@ -693,6 +714,23 @@ const routingTable = () => [ } ] }, + { + issPageValue: issPageValues.PAYMENT_RETURN_ADYEN, + maps: [ + { + scenario: navigationScenarios.PAY_IN_ADVANCE_CANCEL, + destinationIssPageValue: issPageValues.PAYMENT_PAGE_ADYEN + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_ERROR, + destinationIssPageValue: issPageValues.PAYMENT_PAGE_ADYEN + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS, + destinationIssPageValue: issPageValues.ORDER_CONFIRMATION + } + ] + }, { issPageValue: issPageValues.TPA_CONFIRMATION, maps: [ diff --git a/src/store/index.js b/src/store/index.js index 59df6e99..b628cd16 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1778,6 +1778,9 @@ export const useMainStore = defineStore({ updatePaypalToken(token) { this.order.payment.paypalToken = token; }, + updateNextGenSettledAmount(amount) { + this.order.payment.nextGenSettledAmount = amount; + }, setSaveSessionPromise(promise) { this.applicationUser.saveSessionPromise = promise; }, @@ -2896,6 +2899,33 @@ export const useMainStore = defineStore({ endpoint: endpoints.GetPaymentSignature.url }); }, + async initializeAdyenPayment(requestBody) { + const response = await globalMethods.callHttpClient({ + method: endpoints.InitializeAdyenPayment.method, + endpoint: endpoints.InitializeAdyenPayment.url, + payload: requestBody, + logApiCall: true + }); + return response.data; + }, + async getAdyenSessionResult(paymentSessionRequest) { + const response = await globalMethods.callHttpClient({ + method: endpoints.GetAdyenSessionResult.method, + endpoint: endpoints.GetAdyenSessionResult.url, + payload: paymentSessionRequest, + logApiCall: true + }); + return response.data; + }, + async getAdyenSessionResult(paymentSessionRequest) { + const response = await globalMethods.callHttpClient({ + method: endpoints.GetAdyenSessionResult.method, + endpoint: endpoints.GetAdyenSessionResult.url, + payload: paymentSessionRequest, + logApiCall: true + }); + return response.data; + }, hasSubmittedOrder() { return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; diff --git a/vue.config.js b/vue.config.js index 3e5f6ffa..d9d97c60 100644 --- a/vue.config.js +++ b/vue.config.js @@ -3,6 +3,8 @@ process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost'; process.env.VUE_APP_CUSTOMER_PORTAL_URL = 'https://myaccountdev.safelite.com/'; process.env.VUE_APP_GOOGLE_PLACES_API_KEY = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0'; process.env.VUE_APP_SAFELITE_HOP = 'https://iss-hop-dev.glassclaim.com/fmgCheckoutShared.aspx'; +process.env.VUE_APP_ADYEN_ENVIRONMENT = 'test'; +process.env.VUE_APP_ADYEN_CLIENT_KEY = 'test_WYGT4F5ZT5BRRL5MPWHK6QLYOIXZXROD'; // GA & GTM // NOTE: Using the old ISS site GTM Cotnainer ID for now, will create a new one soon. From aac6cd1dea95ba7bfb36de31be0f2239cee91256 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Tue, 17 Mar 2026 10:00:13 -0400 Subject: [PATCH 2/5] INSR-7995: Address copilot comments --- src/constants/progress-bar-mapper.js | 6 ++- src/helpers/adyen-helper.js | 12 +---- .../payment-page-adyen/payment-page-adyen.vue | 51 ++++--------------- .../payment-return-adyen.vue | 31 +---------- src/store/index.js | 9 ---- 5 files changed, 19 insertions(+), 90 deletions(-) diff --git a/src/constants/progress-bar-mapper.js b/src/constants/progress-bar-mapper.js index 935c3b38..f9b6b7e0 100644 --- a/src/constants/progress-bar-mapper.js +++ b/src/constants/progress-bar-mapper.js @@ -66,7 +66,11 @@ export const pageProgressMapper = { // No progress bar on this page percent: 0 }, - 'payment-adyen': { + 'payment-page-adyen': { + // No progress bar on this page + percent: 0 + }, + 'payment-return-adyen': { // No progress bar on this page percent: 0 }, diff --git a/src/helpers/adyen-helper.js b/src/helpers/adyen-helper.js index 1cc719d2..76ad22ad 100644 --- a/src/helpers/adyen-helper.js +++ b/src/helpers/adyen-helper.js @@ -6,9 +6,7 @@ import { AppointmentTypeStrings } from "@/constants/schedule-constants"; import { paymentMethods } from "@/constants/payment-method-constants"; import applicationConfig from "@/constants/application-config"; -export async function getNewSession(sessionConfig) {} - -export async function getSessionInfo(sessionId, encryptedSessionResult, pageNameToLog = "") { +export async function getSessionInfo(sessionId, encryptedSessionResult) { const order = useMainStore().order; const location = getLocationInfo(order); const workOrder = getWorkOrderLastSixDigits(order); @@ -26,8 +24,7 @@ export async function getSessionInfo(sessionId, encryptedSessionResult, pageName method: endpoints.GetAdyenSessionResult.method, endpoint: endpoints.GetAdyenSessionResult.url, payload: request, - logApiCall: true, - pageNameToLog: pageNameToLog, + logApiCall: true }); return response?.data; @@ -65,9 +62,6 @@ export async function createAdyenCheckout({ }; } - console.log(`Creating checkout with configuration:`); - console.log(config); - return await AdyenCheckout(config); } @@ -102,8 +96,6 @@ export function mapIssToAdyenPaymentMethod(issMethod) { export function generateCcToken(adyenSessionInfo) { const order = useMainStore().order; const locationInfo = getLocationInfo(order); - console.log("Generating CC Token with the following Adyen Session Info:"); - console.log(JSON.parse(JSON.stringify(adyenSessionInfo))); const ccToken = { subscriptionId: adyenSessionInfo?.storedToken, diff --git a/src/layouts/payment-page-adyen/payment-page-adyen.vue b/src/layouts/payment-page-adyen/payment-page-adyen.vue index afc42249..42278c31 100644 --- a/src/layouts/payment-page-adyen/payment-page-adyen.vue +++ b/src/layouts/payment-page-adyen/payment-page-adyen.vue @@ -50,7 +50,6 @@ // Components import siteHeader from '@/iss-components/site-header/site-header.vue'; import siteFooter from '@/iss-components/site-footer/site-footer.vue'; -import buttonMain from '@/ux-components/button-main/button-main.vue'; import alert from '@/ux-components/alert/alert.vue'; import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue'; @@ -146,8 +145,14 @@ export default { dropinComponent: null, sourceSystem: 'ISS-NextGen', hasPaymentFailureError: false, + adyenTimeout: null }; }, + unmounted() { + if (this.adyenTimeout) { + clearTimeout(this.adyenTimeout); + } + }, computed: { piaType() { return this.mainStore.payment.paymentMethod; @@ -196,7 +201,7 @@ export default { const tokens = address.split(" ") ?? [""]; const number = tokens[0]; - const street = tokens.slice(1).reduce((prev, next) => `${prev} ${next}`); + const street = tokens.slice(1).join(" ") ?? ""; return { number: number ?? "", @@ -366,19 +371,10 @@ export default { ); }, async initializeAdyen() { - console.log(`Price = ${this.totalAmount}`); - console.log(`Adyen Price = ${this.adyenPriceTotal}`); - const requestBody = this.getAdyenInitRequestInfo(); - - console.log(`Calling with:`); - console.log(requestBody); const adyenResponse = await this.mainStore.initializeAdyenPayment(requestBody); - console.log(`Got data:`); - console.log(adyenResponse); - const session = { id: adyenResponse.sessionId, sessionData: adyenResponse.sessionData, @@ -390,15 +386,12 @@ export default { session: session, handlers: { onPaymentCompleted: (result, component) => { - console.log(`Payment completed from Adyen.`); this.handleCompletedPayment(result); }, onPaymentFailed: (result, component) => { - console.log(`Payment failed from Adyen`); this.handleFailedPayment(result); }, onError: (error, component) => { - console.log(`Error from Adyen`); this.handleError(error); }, }, @@ -407,8 +400,6 @@ export default { }, }); - console.log(checkout); - const expiryTime = new Date(checkout.options.expiresAt); const expiryInterval = expiryTime.getTime() - new Date().getTime(); @@ -416,7 +407,10 @@ export default { this.resetAdyenDropin(); }; - const timeout = setTimeout(handleTimeout, expiryInterval); + if (this.adyenTimeout) { + clearTimeout(this.adyenTimeout); + } + this.adyenTimeout = setTimeout(handleTimeout, expiryInterval); const configuration = { paymentMethodsConfiguration: { @@ -449,9 +443,7 @@ export default { }, }; - console.log(`PIA Type: ${this.piaType}`); const adyenPaymentType = mapIssToAdyenPaymentMethod(this.piaType); - console.log(`Adyen payment type: ${adyenPaymentType}`); if (adyenPaymentType) { configuration.openPaymentMethod = { @@ -461,9 +453,6 @@ export default { const dropin = new Dropin(checkout, configuration); - console.log(`Mounting Adyen dropin`); - console.log(dropin); - this.dropinComponent = dropin; dropin.mount("#adyen-container"); @@ -487,8 +476,6 @@ export default { lastName: this.mainStore.contactInfo.lastName, idempotencyKey: this.getIdempotencyKey(), }; - console.log(`Adyen init request info:`); - console.log(request); return request; }, async resetAdyenDropin() { @@ -506,8 +493,6 @@ export default { return `${id}-${system}-${currentDate}-${currentHour}-${total}`; }, async handleCompletedPayment(result) { - console.log(`Result =`); - console.log(result); // Fetch session info const paymentSessionRequest = { zipCodeCtu: this.ctu, @@ -517,16 +502,10 @@ export default { sessionResult: result?.sessionResult, }; - console.log(`Get session payload =`); - console.log(paymentSessionRequest); - showIssLoadingModal(true); const adyenResponse = await this.mainStore.getAdyenSessionResult(paymentSessionRequest); - console.log(`Session response =`); - console.log(adyenResponse); - const ccToken = { subscriptionId: adyenResponse?.storedToken, expMonth: adyenResponse?.cardExpiryMonth, @@ -542,9 +521,6 @@ export default { lastFour: adyenResponse?.last4DigitsOfCard, }; - console.log(`CC Token generated =`); - console.log(ccToken); - const paymentMethodFromSession = adyenResponse?.paymentMethod; const paymentMethod = mapAdyenToIssPaymentMethod(paymentMethodFromSession); @@ -562,9 +538,6 @@ export default { await this.saveAndSubmitWorkOrder(); }, async handleFailedPayment(result) { - console.log(`Result =`); - console.log(result); - const wasPaymentCancelled = result?.resultCode === "Cancelled"; if (!wasPaymentCancelled) { @@ -578,8 +551,6 @@ export default { this.dropinComponent?.update(); }, async handleError(error) { - console.log(error); - const wasPaymentCancelled = error?.name === "CANCEL"; if (!wasPaymentCancelled) { diff --git a/src/layouts/payment-return-adyen/payment-return-adyen.vue b/src/layouts/payment-return-adyen/payment-return-adyen.vue index b84bcb5c..bbbf46bb 100644 --- a/src/layouts/payment-return-adyen/payment-return-adyen.vue +++ b/src/layouts/payment-return-adyen/payment-return-adyen.vue @@ -27,7 +27,6 @@ export default { async mounted() { showIssLoadingModal(true); const store = useMainStore(); - console.log(`In adyen return.`); const sessionId = this.$route?.query?.sessionId; const redirectResult = this.$route?.query?.redirectResult; @@ -36,20 +35,16 @@ export default { let result = null; try { - console.log(`Finalizing Adyen payment with sessionId ${sessionId} and redirectResult ${redirectResult}`); result = await this.finalizeAdyenPayment(sessionId, redirectResult); } catch (unexpectedResult) { - console.log(`Payment finalization failed with result:`); - console.log(unexpectedResult); // If user cancelled payment, handle without error message if (unexpectedResult.code === "Cancelled" || unexpectedResult.code === "CANCEL") { - console.log(`Payment was cancelled by user.`); this.$router.navigate(navigationScenarios.PAY_IN_ADVANCE_CANCEL, this.$route); return; } // Otherwise, failure scenario. - // Payment fails, so return user to payment-adyen screen to try again or pay later. + // Payment fails, so return user to payment-page-adyen screen to try again or pay later. this.$router.navigate( navigationScenarios.PAY_IN_ADVANCE_ERROR, this.$route, @@ -59,26 +54,13 @@ export default { ); return; } - - console.log(`Out of promise`); - console.log(result); - const sessionInfo = await getSessionInfo(sessionId, result.sessionResult); - console.log(`Got session info:`); - console.log(sessionInfo); - // TODO once afterpay info is returned, create cc token and submit order. const paymentMethod = mapAdyenToIssPaymentMethod(sessionInfo?.paymentMethod); const amountDue = getCartTotal(store.order); const ccToken = generateCcToken(sessionInfo); - ccToken.authCode = "831001"; - ccToken.cardType = "VS"; - ccToken.lastFour = "1111"; - ccToken.expMonth = "03"; - ccToken.expYear = "2030"; - store.savePaymentMethodChoice(paymentMethod); store.updateCreditCardToken(ccToken); store.updateNextGenSettledAmount(amountDue); @@ -88,7 +70,6 @@ export default { await this.saveAndSubmitWorkOrder(); return; } catch (error) { - console.log(error); this.$router.navigate( navigationScenarios.PAY_IN_ADVANCE_ERROR, this.$route, @@ -116,14 +97,9 @@ export default { }, handlers: { onPaymentCompleted: (result, component) => { - console.log(`Payment successful`); - console.log(result); resolve(result); }, onPaymentFailed: (result, component) => { - console.log(`Payment failed`); - console.log(result); - if (result?.resultCode !== "Cancelled") { const stringToLog = `ADYEN PAYMENT NOT AUTHORIZED. Code = ${result?.resultCode}. Id = ${sessionId}`; @@ -136,9 +112,6 @@ export default { }); }, onError: (error, component) => { - console.log(`Error occured`); - console.log(error); - if (error?.name !== "CANCEL") { const stringToLog = `ADYEN ERROR. Name = ${error?.name}. Details = ${error?.message}.`; @@ -154,7 +127,6 @@ export default { options: {}, }).then( (checkout) => { - console.log(`Submitting details to Adyen checkout`); checkout.submitDetails({ details: { redirectResult: redirectResult, @@ -162,7 +134,6 @@ export default { }); }, (error) => { - console.log(`Failed to create Adyen checkout`); reject(error); } ); diff --git a/src/store/index.js b/src/store/index.js index b628cd16..9098cd8c 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2917,15 +2917,6 @@ export const useMainStore = defineStore({ }); return response.data; }, - async getAdyenSessionResult(paymentSessionRequest) { - const response = await globalMethods.callHttpClient({ - method: endpoints.GetAdyenSessionResult.method, - endpoint: endpoints.GetAdyenSessionResult.url, - payload: paymentSessionRequest, - logApiCall: true - }); - return response.data; - }, hasSubmittedOrder() { return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; From 5a795744eeea2e69dd918fee86ad162ce976848a Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Tue, 17 Mar 2026 12:22:49 -0400 Subject: [PATCH 3/5] INSR-7995: Remove unnecessary IP in request body --- src/layouts/payment-page-adyen/payment-page-adyen.vue | 1 - src/layouts/payment-return-adyen/payment-return-adyen.vue | 1 - 2 files changed, 2 deletions(-) diff --git a/src/layouts/payment-page-adyen/payment-page-adyen.vue b/src/layouts/payment-page-adyen/payment-page-adyen.vue index 42278c31..6a2db11d 100644 --- a/src/layouts/payment-page-adyen/payment-page-adyen.vue +++ b/src/layouts/payment-page-adyen/payment-page-adyen.vue @@ -471,7 +471,6 @@ export default { stateOrProvince: this.state, returnUrl: this.payInAdvanceResponseUrl, email: this.mainStore.contactInfo.emailAddress, - IP: "127.0.0.1", // TODO firstName: this.mainStore.contactInfo.firstName, lastName: this.mainStore.contactInfo.lastName, idempotencyKey: this.getIdempotencyKey(), diff --git a/src/layouts/payment-return-adyen/payment-return-adyen.vue b/src/layouts/payment-return-adyen/payment-return-adyen.vue index bbbf46bb..52a9d753 100644 --- a/src/layouts/payment-return-adyen/payment-return-adyen.vue +++ b/src/layouts/payment-return-adyen/payment-return-adyen.vue @@ -56,7 +56,6 @@ export default { } const sessionInfo = await getSessionInfo(sessionId, result.sessionResult); - // TODO once afterpay info is returned, create cc token and submit order. const paymentMethod = mapAdyenToIssPaymentMethod(sessionInfo?.paymentMethod); const amountDue = getCartTotal(store.order); const ccToken = generateCcToken(sessionInfo); From ab565fccec4f55c618b0babd0f9f8beae5820af6 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Tue, 17 Mar 2026 13:15:51 -0400 Subject: [PATCH 4/5] INSR-7995: Address some inconsistencies --- src/helpers/adyen-helper.js | 11 ++++++----- src/layouts/payment-method/payment-method.vue | 5 +++-- src/layouts/payment-page-adyen/payment-page-adyen.vue | 8 ++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/helpers/adyen-helper.js b/src/helpers/adyen-helper.js index 76ad22ad..d1b5b571 100644 --- a/src/helpers/adyen-helper.js +++ b/src/helpers/adyen-helper.js @@ -94,17 +94,18 @@ export function mapIssToAdyenPaymentMethod(issMethod) { } export function generateCcToken(adyenSessionInfo) { - const order = useMainStore().order; - const locationInfo = getLocationInfo(order); + const zipCode = useMainStore().order.customer.address.zipCode + ?? useMainStore().order.serviceLocation.zipCode + ?? useMainStore().order.serviceLocation.provider.address.zipCode const ccToken = { subscriptionId: adyenSessionInfo?.storedToken, expMonth: adyenSessionInfo?.cardExpiryMonth, expYear: adyenSessionInfo?.cardExpiryYear, cardType: adyenSessionInfo?.cardType, - billToPostalCode: locationInfo.zipCode, // TODO - real data? - billToFirstName: order.customer.firstName, // TODO - real data? - billToLastName: order.customer.lastName, // TODO - real data? + billToPostalCode: zipCode, + billToFirstName: useMainStore().contactInfo.firstName, + billToLastName: useMainStore().contactInfo.lastName, referenceNumber: adyenSessionInfo?.workOrderNumber, authCode: adyenSessionInfo?.authCode, transactionId: adyenSessionInfo?.transactionReference, diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 0c3d0c7d..67c09971 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -240,8 +240,9 @@ export default { return !isEnabled || useMainStore().isUnverified || (useMainStore().isDeductible && isDeductibleTotalEqualToZero); }, isAdyenEnabled() { - const adyenEnabled = this.getSettingValue(experimentSettings.ISS_ENABLE_ADYEN_V1); - return adyenEnabled === 'true'; + return true; + // const adyenEnabled = this.getSettingValue(experimentSettings.ISS_ENABLE_ADYEN_V1); + // return adyenEnabled === 'true'; }, paymentMethodWidgetName() { let showApplePay = false; diff --git a/src/layouts/payment-page-adyen/payment-page-adyen.vue b/src/layouts/payment-page-adyen/payment-page-adyen.vue index 6a2db11d..91462f51 100644 --- a/src/layouts/payment-page-adyen/payment-page-adyen.vue +++ b/src/layouts/payment-page-adyen/payment-page-adyen.vue @@ -510,12 +510,12 @@ export default { expMonth: adyenResponse?.cardExpiryMonth, expYear: adyenResponse?.cardExpiryYear, cardType: adyenResponse?.cardType, - billToPostalCode: this.zipCode, // TODO - billToFirstName: this.mainStore.contactInfo.firstName, // TODO - billToLastName: this.mainStore.contactInfo.lastName, // TODO + billToPostalCode: this.zipCode, + billToFirstName: this.mainStore.contactInfo.firstName, + billToLastName: this.mainStore.contactInfo.lastName, referenceNumber: adyenResponse?.workOrderNumber, authCode: adyenResponse?.authCode, - transactionId: adyenResponse?.transactionReference, // TODO + transactionId: adyenResponse?.transactionReference, transReferenceNumber: adyenResponse?.transactionReference, lastFour: adyenResponse?.last4DigitsOfCard, }; From 91858f1d284a50d54a68d1b04de23a995db30568 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Wed, 18 Mar 2026 11:37:39 -0400 Subject: [PATCH 5/5] INSR-7995: Fix an issue with AfterPay --- src/layouts/payment-method/payment-method.vue | 5 ++--- src/layouts/payment-return-adyen/payment-return-adyen.vue | 8 ++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 67c09971..0c3d0c7d 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -240,9 +240,8 @@ export default { return !isEnabled || useMainStore().isUnverified || (useMainStore().isDeductible && isDeductibleTotalEqualToZero); }, isAdyenEnabled() { - return true; - // const adyenEnabled = this.getSettingValue(experimentSettings.ISS_ENABLE_ADYEN_V1); - // return adyenEnabled === 'true'; + const adyenEnabled = this.getSettingValue(experimentSettings.ISS_ENABLE_ADYEN_V1); + return adyenEnabled === 'true'; }, paymentMethodWidgetName() { let showApplePay = false; diff --git a/src/layouts/payment-return-adyen/payment-return-adyen.vue b/src/layouts/payment-return-adyen/payment-return-adyen.vue index 52a9d753..d306857d 100644 --- a/src/layouts/payment-return-adyen/payment-return-adyen.vue +++ b/src/layouts/payment-return-adyen/payment-return-adyen.vue @@ -17,6 +17,7 @@ import { createAdyenCheckout, generateCcToken, getSessionInfo, mapAdyenToIssPaym import navigationScenarios from '@/router/router-constants/navigation-scenarios'; import submitType from '@/constants/submit-type'; import showIssLoadingModal from '@/helpers/loading-modal-helper'; +import { paymentMethods } from '@/constants/payment-method-constants'; export default { name: 'payment-return-adyen', @@ -59,6 +60,13 @@ export default { const paymentMethod = mapAdyenToIssPaymentMethod(sessionInfo?.paymentMethod); const amountDue = getCartTotal(store.order); const ccToken = generateCcToken(sessionInfo); + if (paymentMethod === paymentMethods.AFTERPAY) { + ccToken.authCode = "831001"; + ccToken.cardType = "VS"; + ccToken.lastFour = "1111"; + ccToken.expMonth = "03"; + ccToken.expYear = "2030"; + } store.savePaymentMethodChoice(paymentMethod); store.updateCreditCardToken(ccToken);