Merge pull request #1142 from Safelite/feature/humphries/INSR-7995
INSR-7995: Adyen integration
This commit is contained in:
commit
2c488803bd
15 changed files with 1099 additions and 5 deletions
41
package-lock.json
generated
41
package-lock.json
generated
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -66,6 +66,14 @@ export const pageProgressMapper = {
|
|||
// No progress bar on this page
|
||||
percent: 0
|
||||
},
|
||||
'payment-page-adyen': {
|
||||
// No progress bar on this page
|
||||
percent: 0
|
||||
},
|
||||
'payment-return-adyen': {
|
||||
// No progress bar on this page
|
||||
percent: 0
|
||||
},
|
||||
'tpa-search': {
|
||||
percent: 80
|
||||
},
|
||||
|
|
|
|||
164
src/helpers/adyen-helper.js
Normal file
164
src/helpers/adyen-helper.js
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
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 getSessionInfo(sessionId, encryptedSessionResult) {
|
||||
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
|
||||
});
|
||||
|
||||
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",
|
||||
};
|
||||
}
|
||||
|
||||
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 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: zipCode,
|
||||
billToFirstName: useMainStore().contactInfo.firstName,
|
||||
billToLastName: useMainStore().contactInfo.lastName,
|
||||
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";
|
||||
}
|
||||
|
|
@ -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 }
|
||||
|
|
|
|||
623
src/layouts/payment-page-adyen/payment-page-adyen.vue
Normal file
623
src/layouts/payment-page-adyen/payment-page-adyen.vue
Normal file
|
|
@ -0,0 +1,623 @@
|
|||
<template>
|
||||
<Form>
|
||||
<div class="fade-on-route-transition">
|
||||
<div class="justify-content-center">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
<div class="iss-heritage-container-width payment-page-container">
|
||||
<div id="card-container" class="row">
|
||||
<div class="col-lg-8">
|
||||
<alert
|
||||
v-if="hasPaymentFailureError"
|
||||
name="payInAdvanceErrorAlert"
|
||||
class="pay-in-advance-alert"
|
||||
cmsWidgetName="PayInAdvanceErrorAlertWidget"
|
||||
alertClass="alert-danger"
|
||||
:isDismissible="false"
|
||||
:isCollapsible="true"
|
||||
:preventDefaultOnClick="true"
|
||||
@textLinkClicked="paymentFailedPayLater" />
|
||||
<div id="adyen-container"></div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-10 col-xs-12">
|
||||
<div class="order-summary-panel">
|
||||
<div class="cart-title">{{ cartTitle }}</div>
|
||||
<cartDropdown
|
||||
ref="cart"
|
||||
class="cart-dropdown-component"
|
||||
:readOnly="true"
|
||||
:showAsPaid="false"
|
||||
recyclingModalCmsWidgetName="RecycleModal"
|
||||
servicePackageTitleWidgetName="ServicePackageTitle" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<siteFooter
|
||||
class="footer-component"
|
||||
ref="siteFooter"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="true"
|
||||
:isForwardButtonHidden="true"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
@backClicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</template>
|
||||
<script>
|
||||
// Components
|
||||
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
||||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||
import alert from '@/ux-components/alert/alert.vue';
|
||||
import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
|
||||
|
||||
// Supporting files
|
||||
import issPageValues from '@/router/router-constants/issPage-values.js';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import settleAllPromises from '@/helpers/layout-helper';
|
||||
import { Form } from 'vee-validate';
|
||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||
import { getCartTotal } from '@/helpers/cart-helper';
|
||||
import { useMainStore } from '@/store';
|
||||
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||
import { paymentMethods } from '@/constants/payment-method-constants.js';
|
||||
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
|
||||
import queryStrings from '@/constants/query-strings';
|
||||
import { formatAmountInDollars } from '@/helpers/text-helper';
|
||||
import showIssLoadingModal from '@/helpers/loading-modal-helper';
|
||||
import { submitWorkOrder } from '@/helpers/order-helper';
|
||||
import submitType from '@/constants/submit-type';
|
||||
|
||||
import "@adyen/adyen-web/styles/adyen.css";
|
||||
import { mapAdyenToIssPaymentMethod, mapIssToAdyenPaymentMethod } from '@/helpers/adyen-helper';
|
||||
import { createAdyenCheckout } from "@/helpers/adyen-helper";
|
||||
import { Dropin } from "@adyen/adyen-web/auto";
|
||||
import applicationConfig from '@/constants/application-config';
|
||||
|
||||
export default {
|
||||
name: 'payment-page-adyen',
|
||||
components: {
|
||||
cartDropdown,
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
Form,
|
||||
alert
|
||||
},
|
||||
mixins: [BaseFormMixin],
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
const alertToDisplay = to.query[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT];
|
||||
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
||||
// Settle promises and get results
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: 'cmsContent',
|
||||
promise: cmsContentPromise
|
||||
}
|
||||
];
|
||||
|
||||
// use resultMap to populate layout content.
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
vm.$nextTick(() => {
|
||||
if (vm.$refs.cart) {
|
||||
const cartItems = vm.$refs.cart.cartItems;
|
||||
vm.getPayInAdvanceLineItems(cartItems);
|
||||
}
|
||||
if (alertToDisplay) {
|
||||
vm.hasPaymentFailureError = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
showIssLoadingModal(true);
|
||||
this.initializeAdyen().finally(() => {
|
||||
showIssLoadingModal(false);
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
referralSequenceNumber: useMainStore().order.referralSequenceNumber,
|
||||
emailAddress: useMainStore().contactInfo.emailAddress,
|
||||
address1: this.getAddress1(),
|
||||
address2: this.getAddress2(),
|
||||
city: this.getCity(),
|
||||
state: this.getState(),
|
||||
zipCode: this.getZipCode(),
|
||||
firstName: useMainStore().contactInfo.firstName,
|
||||
lastName: useMainStore().contactInfo.lastName,
|
||||
phoneNumber: useMainStore().contactInfo.servicePhone,
|
||||
ctu: useMainStore().order.serviceLocation.provider?.address?.zipCodeCtu ?? useMainStore().order.serviceLocation.zipCodeCtu,
|
||||
referralCorrelationId: useMainStore().order.referralCorrelationId,
|
||||
workOrderNumber: this.getWorkOrderNumber(),
|
||||
invoiceNumber: this.getInvoiceNumber(),
|
||||
totalAmount: this.getAmountDue(),
|
||||
displayAmount: this.getDisplayAmountDue(),
|
||||
payInAdvanceLineItems: '',
|
||||
sessionId: '',
|
||||
dropinComponent: null,
|
||||
sourceSystem: 'ISS-NextGen',
|
||||
hasPaymentFailureError: false,
|
||||
adyenTimeout: null
|
||||
};
|
||||
},
|
||||
unmounted() {
|
||||
if (this.adyenTimeout) {
|
||||
clearTimeout(this.adyenTimeout);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
piaType() {
|
||||
return this.mainStore.payment.paymentMethod;
|
||||
},
|
||||
parentDomainName() {
|
||||
return window.location.hostname;
|
||||
},
|
||||
payInAdvanceResponseUrl() {
|
||||
const { protocol, host } = window.location;
|
||||
return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_RETURN_ADYEN}&src=iss-nextgen`;
|
||||
},
|
||||
payInAdvanceCancelUrl() {
|
||||
const { protocol, host } = window.location;
|
||||
return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_METHOD}&src=iss-nextgen`;
|
||||
},
|
||||
cartTitle() {
|
||||
return this.getCmsContent('OrderSummaryTextWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
},
|
||||
switchPaymentText() {
|
||||
return this.getCmsContent('SwitchPaymentTextWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
},
|
||||
submitPaymentText() {
|
||||
return this.getCmsContent('SiteFooterWidget', widgetFields.FOOTER_WIDGET.FORWARD_BUTTON_TEXT);
|
||||
},
|
||||
adyenPriceTotal() {
|
||||
return Math.round(this.totalAmount * 100);
|
||||
},
|
||||
workOrderNumberLastSixDigits() {
|
||||
const workOrderNumber = this.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;
|
||||
},
|
||||
splitStreetAddress() {
|
||||
const address = this.address1;
|
||||
const tokens = address.split(" ") ?? [""];
|
||||
const number = tokens[0];
|
||||
|
||||
const street = tokens.slice(1).join(" ") ?? "";
|
||||
|
||||
return {
|
||||
number: number ?? "",
|
||||
street: street ?? "",
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
// Line Items
|
||||
const packageReqs =
|
||||
!!useMainStore().order.lineItems.supportingItems;
|
||||
|
||||
// Service Location
|
||||
const { serviceLocation } = useMainStore().order;
|
||||
const mobileReqs = !!(
|
||||
serviceLocation.address
|
||||
&& serviceLocation.city
|
||||
&& serviceLocation.state
|
||||
&& serviceLocation.zipCode
|
||||
);
|
||||
|
||||
const providerLocation = serviceLocation.provider.address;
|
||||
const dropOffInshopReqs = !!(
|
||||
providerLocation.streetAddress
|
||||
&& providerLocation.city
|
||||
&& providerLocation.state
|
||||
&& providerLocation.zipCode
|
||||
);
|
||||
|
||||
const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|
||||
|| serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP;
|
||||
|
||||
const serviceLocationReqs =
|
||||
(isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs);
|
||||
|
||||
// Insurance
|
||||
const isInsuranceSet =
|
||||
useMainStore().order.payment.isInsurance !== null;
|
||||
|
||||
// Schedule
|
||||
const { schedule } = useMainStore().order;
|
||||
const scheduleReqs = !!(
|
||||
schedule.date
|
||||
&& schedule.startTime
|
||||
&& schedule.endTime
|
||||
&& schedule.jobMaxMinutes
|
||||
&& schedule.jobMinMinutes
|
||||
);
|
||||
|
||||
// Contact Info
|
||||
const { contactInfo } = useMainStore();
|
||||
const contactInfoReqs = !!(
|
||||
contactInfo.firstName
|
||||
&& contactInfo.lastName
|
||||
&& contactInfo.servicePhone
|
||||
&& contactInfo.emailAddress
|
||||
);
|
||||
|
||||
const paymentMethodReqs = useMainStore().isPayInAdvance;
|
||||
|
||||
return (
|
||||
packageReqs
|
||||
&& serviceLocationReqs
|
||||
&& isInsuranceSet
|
||||
&& scheduleReqs
|
||||
&& contactInfoReqs
|
||||
&& paymentMethodReqs
|
||||
);
|
||||
},
|
||||
getWorkOrderNumber() {
|
||||
const { workOrderNumber } = useMainStore().order;
|
||||
if (workOrderNumber) {
|
||||
const items = workOrderNumber.split('-');
|
||||
if (items.length > 1) {
|
||||
return items[1];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
getInvoiceNumber() {
|
||||
const { workOrderNumber } = useMainStore().order;
|
||||
if (workOrderNumber) {
|
||||
return workOrderNumber.replace('-', '');
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
getAddress1() {
|
||||
return (
|
||||
useMainStore().order.serviceLocation.address
|
||||
?? useMainStore().order.serviceLocation.provider.address
|
||||
.streetAddress
|
||||
);
|
||||
},
|
||||
getAddress2() {
|
||||
return useMainStore().order.serviceLocation.address2;
|
||||
},
|
||||
getCity() {
|
||||
return (
|
||||
useMainStore().order.serviceLocation.city
|
||||
?? useMainStore().order.serviceLocation.provider.address.city
|
||||
);
|
||||
},
|
||||
getState() {
|
||||
return (
|
||||
useMainStore().order.serviceLocation.state
|
||||
?? useMainStore().order.serviceLocation.provider.address.state
|
||||
);
|
||||
},
|
||||
getZipCode() {
|
||||
return (
|
||||
useMainStore().order.customer.address.zipCode
|
||||
?? useMainStore().order.serviceLocation.zipCode
|
||||
?? useMainStore().order.serviceLocation.provider.address.zipCode
|
||||
);
|
||||
},
|
||||
getPayInAdvanceLineItems(cartItems) {
|
||||
const { glassParts } = useMainStore().order.lineItems;
|
||||
const lineItems =
|
||||
glassParts === null
|
||||
? [
|
||||
this.getPayInAdvanceFormattedLineItem('Labor', 0, 1),
|
||||
this.getPayInAdvanceFormattedLineItem('Repair supplies', 0, 1)
|
||||
]
|
||||
: [
|
||||
this.getPayInAdvanceFormattedLineItem('Parts and labor', 0, 1)
|
||||
];
|
||||
|
||||
cartItems.forEach((item) => {
|
||||
if (item.name !== null && item.category !== 'promos') {
|
||||
lineItems.push(this.getPayInAdvanceFormattedLineItem(
|
||||
item.name,
|
||||
(item.salesTax + item.subTotal).toFixed(2),
|
||||
1
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
this.payInAdvanceLineItems = lineItems.join('||');
|
||||
},
|
||||
getPayInAdvanceFormattedLineItem(itemName, price, quantity) {
|
||||
return `${itemName}|${price}|${quantity}`;
|
||||
},
|
||||
getAmountDue() {
|
||||
return getCartTotal(useMainStore().order);
|
||||
},
|
||||
getDisplayAmountDue() {
|
||||
return formatAmountInDollars(this.getAmountDue());
|
||||
},
|
||||
async paymentFailedPayLater() {
|
||||
this.showIssLoadingModal(true);
|
||||
this.mainStore.savePaymentMethodChoice(paymentMethods.PAY_AT_TIME_OF_SERVICE);
|
||||
await submitWorkOrder({ submitType: submitType.SAFELITE });
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.$route
|
||||
);
|
||||
},
|
||||
backButtonAction() {
|
||||
// page will not render with normal navigation due to navigating from the iframe
|
||||
window.location = this.payInAdvanceCancelUrl;
|
||||
},
|
||||
forwardButtonAction() {
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.$route
|
||||
);
|
||||
},
|
||||
async initializeAdyen() {
|
||||
const requestBody = this.getAdyenInitRequestInfo();
|
||||
|
||||
const adyenResponse = await this.mainStore.initializeAdyenPayment(requestBody);
|
||||
|
||||
const session = {
|
||||
id: adyenResponse.sessionId,
|
||||
sessionData: adyenResponse.sessionData,
|
||||
};
|
||||
|
||||
this.sessionId = adyenResponse.sessionId;
|
||||
|
||||
const checkout = await createAdyenCheckout({
|
||||
session: session,
|
||||
handlers: {
|
||||
onPaymentCompleted: (result, component) => {
|
||||
this.handleCompletedPayment(result);
|
||||
},
|
||||
onPaymentFailed: (result, component) => {
|
||||
this.handleFailedPayment(result);
|
||||
},
|
||||
onError: (error, component) => {
|
||||
this.handleError(error);
|
||||
},
|
||||
},
|
||||
options: {
|
||||
amount: this.adyenPriceTotal,
|
||||
},
|
||||
});
|
||||
|
||||
const expiryTime = new Date(checkout.options.expiresAt);
|
||||
const expiryInterval = expiryTime.getTime() - new Date().getTime();
|
||||
|
||||
const handleTimeout = () => {
|
||||
this.resetAdyenDropin();
|
||||
};
|
||||
|
||||
if (this.adyenTimeout) {
|
||||
clearTimeout(this.adyenTimeout);
|
||||
}
|
||||
this.adyenTimeout = setTimeout(handleTimeout, expiryInterval);
|
||||
|
||||
const configuration = {
|
||||
paymentMethodsConfiguration: {
|
||||
ideal: {
|
||||
showImage: true,
|
||||
},
|
||||
paypal: {
|
||||
amount: {
|
||||
value: this.adyenPriceTotal,
|
||||
currency: "USD",
|
||||
},
|
||||
environment: applicationConfig.ADYEN_ENVIRONMENT,
|
||||
countryCode: "US", // Only needed for test. This will be automatically retrieved when you are in production.
|
||||
blockPayPalVenmoButton: true,
|
||||
blockPayPalPayLaterButton: true,
|
||||
},
|
||||
card: {
|
||||
hasHolderName: true,
|
||||
holderNameRequired: true,
|
||||
billingAddressRequired: true,
|
||||
name: "Credit or debit card",
|
||||
data: {
|
||||
holderName: `${this.mainStore.contactInfo.firstName} ${this.mainStore.contactInfo.lastName}`,
|
||||
billingAddress: {
|
||||
postalCode: this.zipCode,
|
||||
country: "US"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const adyenPaymentType = mapIssToAdyenPaymentMethod(this.piaType);
|
||||
|
||||
if (adyenPaymentType) {
|
||||
configuration.openPaymentMethod = {
|
||||
type: adyenPaymentType,
|
||||
};
|
||||
}
|
||||
|
||||
const dropin = new Dropin(checkout, configuration);
|
||||
|
||||
this.dropinComponent = dropin;
|
||||
|
||||
dropin.mount("#adyen-container");
|
||||
},
|
||||
getAdyenInitRequestInfo() {
|
||||
const request = {
|
||||
sourceSystem: this.sourceSystem,
|
||||
referralSequenceNumber: this.referralSequenceNumber,
|
||||
workOrderNumber: this.workOrderNumberLastSixDigits,
|
||||
zipCodeCtu: this.ctu,
|
||||
amount: this.adyenPriceTotal,
|
||||
city: this.city,
|
||||
houseNumberOrName: this.splitStreetAddress.number,
|
||||
street: this.splitStreetAddress.street,
|
||||
zipCode: this.zipCode,
|
||||
stateOrProvince: this.state,
|
||||
returnUrl: this.payInAdvanceResponseUrl,
|
||||
email: this.mainStore.contactInfo.emailAddress,
|
||||
firstName: this.mainStore.contactInfo.firstName,
|
||||
lastName: this.mainStore.contactInfo.lastName,
|
||||
idempotencyKey: this.getIdempotencyKey(),
|
||||
};
|
||||
return request;
|
||||
},
|
||||
async resetAdyenDropin() {
|
||||
this?.dropinComponent?.unmount();
|
||||
await this.initializeAdyen();
|
||||
},
|
||||
getIdempotencyKey() {
|
||||
const currentDateTime = new Date();
|
||||
const currentHour = currentDateTime.getUTCHours();
|
||||
const currentDate = currentDateTime.getUTCDate();
|
||||
const id = this?.mainStore?.order?.referralCorrelationId;
|
||||
const system = this.sourceSystem;
|
||||
const total = this.adyenPriceTotal;
|
||||
|
||||
return `${id}-${system}-${currentDate}-${currentHour}-${total}`;
|
||||
},
|
||||
async handleCompletedPayment(result) {
|
||||
// Fetch session info
|
||||
const paymentSessionRequest = {
|
||||
zipCodeCtu: this.ctu,
|
||||
workOrderNumber: this.workOrderNumberLastSixDigits,
|
||||
sourceSystem: this.sourceSystem,
|
||||
sessionId: this.sessionId,
|
||||
sessionResult: result?.sessionResult,
|
||||
};
|
||||
|
||||
showIssLoadingModal(true);
|
||||
|
||||
const adyenResponse = await this.mainStore.getAdyenSessionResult(paymentSessionRequest);
|
||||
|
||||
const ccToken = {
|
||||
subscriptionId: adyenResponse?.storedToken,
|
||||
expMonth: adyenResponse?.cardExpiryMonth,
|
||||
expYear: adyenResponse?.cardExpiryYear,
|
||||
cardType: adyenResponse?.cardType,
|
||||
billToPostalCode: this.zipCode,
|
||||
billToFirstName: this.mainStore.contactInfo.firstName,
|
||||
billToLastName: this.mainStore.contactInfo.lastName,
|
||||
referenceNumber: adyenResponse?.workOrderNumber,
|
||||
authCode: adyenResponse?.authCode,
|
||||
transactionId: adyenResponse?.transactionReference,
|
||||
transReferenceNumber: adyenResponse?.transactionReference,
|
||||
lastFour: adyenResponse?.last4DigitsOfCard,
|
||||
};
|
||||
|
||||
const paymentMethodFromSession = adyenResponse?.paymentMethod;
|
||||
|
||||
const paymentMethod = mapAdyenToIssPaymentMethod(paymentMethodFromSession);
|
||||
|
||||
this.mainStore.savePaymentMethodChoice(paymentMethod);
|
||||
|
||||
if (paymentMethod === paymentMethods.PAYPAL) {
|
||||
this.mainStore.updatePaypalToken(adyenResponse?.storedToken);
|
||||
} else {
|
||||
this.mainStore.updateCreditCardToken(ccToken);
|
||||
}
|
||||
|
||||
this.mainStore.updateNextGenSettledAmount(this.totalAmount);
|
||||
|
||||
await this.saveAndSubmitWorkOrder();
|
||||
},
|
||||
async handleFailedPayment(result) {
|
||||
const wasPaymentCancelled = result?.resultCode === "Cancelled";
|
||||
|
||||
if (!wasPaymentCancelled) {
|
||||
const stringToLog = `ADYEN PAYMENT NOT AUTHORIZED. Code = ${result?.resultCode}. Id = ${this.sessionId}`;
|
||||
|
||||
await global.$logger.logError(stringToLog);
|
||||
|
||||
this.hasPaymentFailureError = true;
|
||||
}
|
||||
|
||||
this.dropinComponent?.update();
|
||||
},
|
||||
async handleError(error) {
|
||||
const wasPaymentCancelled = error?.name === "CANCEL";
|
||||
|
||||
if (!wasPaymentCancelled) {
|
||||
const stringToLog = `ADYEN ERROR. Name = ${error?.name}. Details = ${error?.message}.`;
|
||||
|
||||
await global.$logger.logError(stringToLog);
|
||||
|
||||
this.hasPaymentFailureError = true;
|
||||
}
|
||||
|
||||
this.dropinComponent?.update();
|
||||
},
|
||||
async saveAndSubmitWorkOrder() {
|
||||
// Final work order submit after returning from pay in advance.
|
||||
await submitWorkOrder({ submitType: submitType.SAFELITE });
|
||||
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.PAY_IN_ADVANCE_SUCCESS,
|
||||
this.$route
|
||||
);
|
||||
},
|
||||
showIssLoadingModal
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.iss-heritage-container-width.payment-page-container {
|
||||
padding: 0 .9375rem;
|
||||
|
||||
#card-container {
|
||||
padding-top: 1.375rem;
|
||||
margin: 0;
|
||||
> * {
|
||||
padding: 0 .9375rem;
|
||||
}
|
||||
}
|
||||
|
||||
.order-summary-panel {
|
||||
margin-bottom: 1.375rem;
|
||||
}
|
||||
|
||||
.cart-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
margin-top: 1.25rem;
|
||||
margin-bottom: .625rem;
|
||||
}
|
||||
|
||||
.cart-dropdown-component.cart-table {
|
||||
font-size: .8125rem;
|
||||
}
|
||||
|
||||
.footer-component:deep(.footer) {
|
||||
margin: 1.25rem 0 0 0;
|
||||
}
|
||||
|
||||
.pay-in-advance-alert {
|
||||
:deep(a) {
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fade-on-route-transition {
|
||||
height: unset;
|
||||
}
|
||||
|
||||
.payment p {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
160
src/layouts/payment-return-adyen/payment-return-adyen.vue
Normal file
160
src/layouts/payment-return-adyen/payment-return-adyen.vue
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<template>
|
||||
<Form
|
||||
ref="theForm"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit">
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Form } from 'vee-validate';
|
||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||
import { useMainStore } from '@/store/index.js';
|
||||
import queryStrings from '@/constants/query-strings';
|
||||
import { getCartTotal } from '@/helpers/cart-helper';
|
||||
import { submitWorkOrder } from '@/helpers/order-helper.js';
|
||||
import { createAdyenCheckout, generateCcToken, getSessionInfo, mapAdyenToIssPaymentMethod } from '@/helpers/adyen-helper';
|
||||
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',
|
||||
components: {
|
||||
Form
|
||||
},
|
||||
mixins: [BaseFormMixin],
|
||||
async mounted() {
|
||||
showIssLoadingModal(true);
|
||||
const store = useMainStore();
|
||||
|
||||
const sessionId = this.$route?.query?.sessionId;
|
||||
const redirectResult = this.$route?.query?.redirectResult;
|
||||
|
||||
if (sessionId && redirectResult) {
|
||||
let result = null;
|
||||
|
||||
try {
|
||||
result = await this.finalizeAdyenPayment(sessionId, redirectResult);
|
||||
} catch (unexpectedResult) {
|
||||
// If user cancelled payment, handle without error message
|
||||
if (unexpectedResult.code === "Cancelled" || unexpectedResult.code === "CANCEL") {
|
||||
this.$router.navigate(navigationScenarios.PAY_IN_ADVANCE_CANCEL, this.$route);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, failure scenario.
|
||||
// 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,
|
||||
{
|
||||
[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
const sessionInfo = await getSessionInfo(sessionId, result.sessionResult);
|
||||
|
||||
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);
|
||||
store.updateNextGenSettledAmount(amountDue);
|
||||
store.clearSaveSessionPromise();
|
||||
|
||||
try {
|
||||
await this.saveAndSubmitWorkOrder();
|
||||
return;
|
||||
} catch (error) {
|
||||
this.$router.navigate(
|
||||
navigationScenarios.PAY_IN_ADVANCE_ERROR,
|
||||
this.$route,
|
||||
{
|
||||
[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.$router.navigate(
|
||||
navigationScenarios.PAY_IN_ADVANCE_ERROR,
|
||||
this.$route,
|
||||
{
|
||||
[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true
|
||||
}
|
||||
);
|
||||
},
|
||||
methods: {
|
||||
finalizeAdyenPayment(sessionId, redirectResult) {
|
||||
return new Promise((resolve, reject) => {
|
||||
createAdyenCheckout({
|
||||
session: {
|
||||
id: sessionId,
|
||||
},
|
||||
handlers: {
|
||||
onPaymentCompleted: (result, component) => {
|
||||
resolve(result);
|
||||
},
|
||||
onPaymentFailed: (result, component) => {
|
||||
if (result?.resultCode !== "Cancelled") {
|
||||
const stringToLog = `ADYEN PAYMENT NOT AUTHORIZED. Code = ${result?.resultCode}. Id = ${sessionId}`;
|
||||
|
||||
global.$logger.logError(stringToLog);
|
||||
}
|
||||
|
||||
reject({
|
||||
code: result?.resultCode,
|
||||
message: "Payment failed from Adyen",
|
||||
});
|
||||
},
|
||||
onError: (error, component) => {
|
||||
if (error?.name !== "CANCEL") {
|
||||
const stringToLog = `ADYEN ERROR. Name = ${error?.name}. Details = ${error?.message}.`;
|
||||
|
||||
global.$logger.logError(stringToLog);
|
||||
}
|
||||
|
||||
reject({
|
||||
code: error?.name,
|
||||
message: "Error from Adyen",
|
||||
});
|
||||
},
|
||||
},
|
||||
options: {},
|
||||
}).then(
|
||||
(checkout) => {
|
||||
checkout.submitDetails({
|
||||
details: {
|
||||
redirectResult: redirectResult,
|
||||
},
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
async saveAndSubmitWorkOrder() {
|
||||
// Final work order submit after returning from pay in advance.
|
||||
await submitWorkOrder({ submitType: submitType.SAFELITE });
|
||||
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.PAY_IN_ADVANCE_SUCCESS,
|
||||
this.$route
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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: [
|
||||
|
|
|
|||
|
|
@ -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,24 @@ 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;
|
||||
},
|
||||
|
||||
hasSubmittedOrder() {
|
||||
return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue