Merge pull request #2971 from Safelite/feature/CASH-1722
Adyen POC - Early Implementation
This commit is contained in:
commit
3131a6dd6e
14 changed files with 695 additions and 3 deletions
41
package-lock.json
generated
41
package-lock.json
generated
|
|
@ -8,6 +8,7 @@
|
|||
"name": "Safelite",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@adyen/adyen-web": "^6.27.0",
|
||||
"@iframe-resizer/child": "^5.3.3",
|
||||
"axios": "^0.30.2",
|
||||
"bootstrap": "^5.3.3",
|
||||
|
|
@ -59,6 +60,18 @@
|
|||
"node": "8 || 9 || 10 || 11 || 12 || 13 || 14 || 15 || 16 || 17 || 18 || 19 || 20 || 21 || 22"
|
||||
}
|
||||
},
|
||||
"node_modules/@adyen/adyen-web": {
|
||||
"version": "6.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@adyen/adyen-web/-/adyen-web-6.27.0.tgz",
|
||||
"integrity": "sha512-6E6hqEkMkoY/FevjO53zhgeCWMt+i/PDc11MX6eVM7Fvd+Sdgc9cIwTBz+NKIXs4ZerG6n2gd+ZIZEywqF/aBQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/applepayjs": "14.0.9",
|
||||
"@types/googlepay": "0.7.8",
|
||||
"classnames": "2.5.1",
|
||||
"preact": "10.22.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
|
|
@ -3173,6 +3186,12 @@
|
|||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"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/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
|
|
@ -3328,6 +3347,12 @@
|
|||
"@types/send": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/googlepay": {
|
||||
"version": "0.7.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/googlepay/-/googlepay-0.7.8.tgz",
|
||||
"integrity": "sha512-EHl7G7jIeit/Px/fi/Du/19SZDvqrRhy0DjJX40Vzs/97m3sro9mzVyAYNC0pfzpWGDY+zPjtTLEfhV+OYWUcQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/graceful-fs": {
|
||||
"version": "4.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
|
||||
|
|
@ -5789,6 +5814,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.3",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
|
||||
|
|
@ -13681,6 +13712,16 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/preact": {
|
||||
"version": "10.22.1",
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.22.1.tgz",
|
||||
"integrity": "sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@adyen/adyen-web": "^6.27.0",
|
||||
"@iframe-resizer/child": "^5.3.3",
|
||||
"axios": "^0.30.2",
|
||||
"bootstrap": "^5.3.3",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ const applicationConfig = {
|
|||
PIA_ERROR_URL:
|
||||
location.protocol + "//" + location.host + "/fmg/payment-pia-return?src=concept-funnel",
|
||||
CONFIRMATION_URL: location.protocol + "//" + location.host + "/fmg/confirmation",
|
||||
PIA_ADYEN_RETURN_URL: location.protocol + "//" + location.host + "/fmg/virtual/payment/return",
|
||||
GOOGLE_CALENDAR: "https://www.google.com/calendar/render?action=TEMPLATE",
|
||||
YAHOO_CALENDAR: "https://calendar.yahoo.com/?v=60",
|
||||
OUTLOOK_CALENDAR:
|
||||
|
|
|
|||
|
|
@ -216,6 +216,14 @@ const endpoints = {
|
|||
url: "/order/api/v1/order/add-donation-part",
|
||||
method: "POST",
|
||||
},
|
||||
InitializeAdyenPayment: {
|
||||
url: "/payment/api/v1/payment/payment/session/initialize-session",
|
||||
method: "POST",
|
||||
},
|
||||
GetAdyenSessionResult: {
|
||||
url: "/payment/api/v1/payment/payment/session/session-result",
|
||||
method: "POST",
|
||||
},
|
||||
};
|
||||
|
||||
export { endpoints };
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ const experimentSettings = {
|
|||
SHOW_PM_MOBILE_DAYS: "Show_PMmobileDays",
|
||||
SHOW_NO_PM_MOBILE_DAYS: "Show_NoPMmobileDays",
|
||||
SHOW_NO_MOBILE_AVAILABLE_DAYS: "Show_NoMobileAvailableDays",
|
||||
USE_ADYEN_PAYMENT: "UseAdyenPayment",
|
||||
};
|
||||
|
||||
const experimentTriggers = {
|
||||
|
|
|
|||
116
src/helpers/adyen-helper.js
Normal file
116
src/helpers/adyen-helper.js
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import { AdyenCheckout } from "@adyen/adyen-web/auto";
|
||||
import store from "@/store";
|
||||
import globalMethods from "@/global-methods";
|
||||
import { endpoints } from "@/constants/endpoints";
|
||||
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
||||
|
||||
export async function getNewSession(sessionConfig) {}
|
||||
|
||||
export async function getSessionInfo(sessionId, encryptedSessionResult, pageNameToLog = "") {
|
||||
const order = store.getters.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: "test_WYGT4F5ZT5BRRL5MPWHK6QLYOIXZXROD",
|
||||
environment: "test",
|
||||
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);
|
||||
}
|
||||
|
||||
function getLocationInfo(order) {
|
||||
const serviceLocation = order.serviceLocation;
|
||||
const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE;
|
||||
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 "FMG-2.0";
|
||||
}
|
||||
410
src/layouts/payment-adyen/payment-adyen.vue
Normal file
410
src/layouts/payment-adyen/payment-adyen.vue
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<funnelSubHeader class="pb-4" cmsWidgetName="FunnelSubHeaderWidget" />
|
||||
<!--
|
||||
... Page code goes here.
|
||||
-->
|
||||
<div id="adyen-container"></div>
|
||||
<navbar
|
||||
cmsWidgetName="FunnelFooterWidget"
|
||||
ref="navbar"
|
||||
isForwardActionDisabled="true"
|
||||
isSubmitHidden="true"
|
||||
@back-clicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<component
|
||||
:is="'script'"
|
||||
src="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/6.21.0/adyen.js"
|
||||
@load="initializeAdyen"></component>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/6.21.0/adyen.css" />
|
||||
</Form>
|
||||
</template>
|
||||
<script>
|
||||
import Form from "vee-validate";
|
||||
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
||||
import navbar from "@/fmg-components/nav-bar/nav-bar";
|
||||
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
||||
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import globalMethods from "@/global-methods";
|
||||
import { endpoints } from "../../constants/endpoints";
|
||||
import { AppointmentTypeStrings } from "../../constants/schedule-constants";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { getAmountDue } from "@/helpers/pricing-helper.js";
|
||||
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
||||
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||
import { createAdyenCheckout } from "@/helpers/adyen-helper";
|
||||
import { Dropin } from "@adyen/adyen-web/auto";
|
||||
import { applicationConfig } from "@/constants/application-config";
|
||||
|
||||
export default {
|
||||
name: "payment-adyen",
|
||||
mixins: [],
|
||||
data() {
|
||||
return {
|
||||
sessionId: String,
|
||||
};
|
||||
},
|
||||
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.name);
|
||||
|
||||
// Settle API calls in parallel before handling results.
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: "cmsContent",
|
||||
promise: cmsContentPromise,
|
||||
},
|
||||
];
|
||||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
// Hydrate page with results
|
||||
next(async (vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
async backButtonAction() {
|
||||
// Stub, for navigating back via nav-bar.
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_BACK,
|
||||
this.pageName
|
||||
);
|
||||
},
|
||||
|
||||
async forwardButtonAction() {
|
||||
// Stub, for navigating forward via nav-bar
|
||||
},
|
||||
|
||||
arePagePrerequisitesValid() {
|
||||
// Stub, for checking if application is capable of entering this page
|
||||
// And/or, is all information required for this page present?
|
||||
// To prevent sequence-breaking from the end-user.
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
async initializeAdyen() {
|
||||
console.log(`Price = ${this.amountDue}`);
|
||||
console.log(`Adyen Price = ${this.adyenPriceTotal}`);
|
||||
|
||||
const requestBody = this.adyenInitRequestInfo;
|
||||
|
||||
console.log(`Calling with:`);
|
||||
console.log(requestBody);
|
||||
|
||||
const response = await globalMethods.callHttpClient({
|
||||
method: endpoints.InitializeAdyenPayment.method,
|
||||
endpoint: endpoints.InitializeAdyenPayment.url,
|
||||
payload: requestBody,
|
||||
logApiCall: true,
|
||||
pageNameToLog: "payment-adyen",
|
||||
});
|
||||
|
||||
const responseJson = response?.data;
|
||||
|
||||
console.log(`Got data:`);
|
||||
console.log(responseJson);
|
||||
|
||||
const session = {
|
||||
id: responseJson.sessionId,
|
||||
sessionData: responseJson.sessionData,
|
||||
};
|
||||
|
||||
this.sessionId = responseJson.sessionId;
|
||||
|
||||
const checkout = await createAdyenCheckout({
|
||||
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);
|
||||
},
|
||||
},
|
||||
options: {
|
||||
amount: this.adyenPriceTotal,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(checkout);
|
||||
|
||||
window.checkout = checkout;
|
||||
const dropin = new Dropin(checkout, {
|
||||
paymentMethodsConfiguration: {
|
||||
ideal: {
|
||||
showImage: true,
|
||||
},
|
||||
paypal: {
|
||||
amount: {
|
||||
value: this.adyenPriceTotal,
|
||||
currency: "USD",
|
||||
},
|
||||
environment: "test", // Change this to "live" when you're ready to accept live PayPal payments
|
||||
countryCode: "US", // Only needed for test. This will be automatically retrieved when you are in production.
|
||||
blockPayPalVenmoButton: false,
|
||||
//blockPayPalPayLaterButton: true
|
||||
},
|
||||
card: {
|
||||
hasHolderName: true,
|
||||
holderNameRequired: true,
|
||||
billingAddressRequired: true,
|
||||
name: "Credit or debit card",
|
||||
},
|
||||
},
|
||||
}).mount("#adyen-container");
|
||||
},
|
||||
|
||||
async handleCompletedPayment(result) {
|
||||
console.log(`Result =`);
|
||||
console.log(result);
|
||||
// Fetch session info
|
||||
const paymentSessionRequest = {
|
||||
zipCodeCtu: this.locationInfo.zipCodeCtu,
|
||||
workOrderNumber: this.workOrderNumberLastSixDigits,
|
||||
sourceSystem: this.sourceSystem,
|
||||
sessionId: this.sessionId,
|
||||
sessionResult: result?.sessionResult,
|
||||
};
|
||||
|
||||
console.log(`Get session payload =`);
|
||||
console.log(paymentSessionRequest);
|
||||
|
||||
const response = await globalMethods.callHttpClient({
|
||||
method: endpoints.GetAdyenSessionResult.method,
|
||||
endpoint: endpoints.GetAdyenSessionResult.url,
|
||||
payload: paymentSessionRequest,
|
||||
logApiCall: true,
|
||||
pageNameToLog: "payment-adyen",
|
||||
});
|
||||
|
||||
const responseJson = response?.data;
|
||||
|
||||
console.log(`Session response =`);
|
||||
console.log(responseJson);
|
||||
|
||||
const ccToken = {
|
||||
subscriptionId: responseJson?.storedToken,
|
||||
expMonth: responseJson?.cardExpiryMonth,
|
||||
expYear: responseJson?.cardExpiryYear,
|
||||
cardType: responseJson?.cardType,
|
||||
billToPostalCode: this.locationInfo.zipCode, // TODO
|
||||
billToFirstName: this.$store.getters.order.customer.firstName, // TODO
|
||||
billToLastName: this.$store.getters.order.customer.lastName, // TODO
|
||||
referenceNumber: responseJson?.workOrderNumber,
|
||||
authCode: responseJson?.authCode,
|
||||
transactionId: responseJson?.transactionReference, // TODO
|
||||
transReferenceNumber: responseJson?.transactionReference,
|
||||
lastFour: responseJson?.last4DigitsOfCard,
|
||||
};
|
||||
|
||||
console.log(`CC Token generated =`);
|
||||
console.log(ccToken);
|
||||
|
||||
// Save payment type.
|
||||
// For now, CC.
|
||||
// Need to determine payment type from Adyen response
|
||||
await this.dispatchStoreAction(
|
||||
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
||||
paymentMethods.CREDIT_CARD,
|
||||
false
|
||||
);
|
||||
|
||||
await baseMixin.methods.dispatchStoreAction(storeActions.SAVE_CCTOKEN, ccToken, false);
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||
this.amountDue,
|
||||
false
|
||||
);
|
||||
|
||||
await this.saveAndSubmitWorkOrder();
|
||||
},
|
||||
async handleFailedPayment(result) {
|
||||
console.log(`Result =`);
|
||||
console.log(result);
|
||||
|
||||
// Fetch session info
|
||||
const paymentSessionRequest = {
|
||||
zipCodeCtu: this.locationInfo.zipCodeCtu,
|
||||
workOrderNumber: this.workOrderNumberLastSixDigits,
|
||||
sourceSystem: this.sourceSystem,
|
||||
sessionId: this.sessionId,
|
||||
sessionResult: result?.sessionResult,
|
||||
};
|
||||
|
||||
console.log(`Get session payload =`);
|
||||
console.log(paymentSessionRequest);
|
||||
|
||||
try {
|
||||
const response = await globalMethods.callHttpClient({
|
||||
method: endpoints.GetAdyenSessionResult.method,
|
||||
endpoint: endpoints.GetAdyenSessionResult.url,
|
||||
payload: paymentSessionRequest,
|
||||
logApiCall: true,
|
||||
pageNameToLog: "payment-adyen",
|
||||
});
|
||||
|
||||
console.log(response);
|
||||
} catch (error) {
|
||||
console.log(`Error getting session info after failure.`);
|
||||
}
|
||||
},
|
||||
handleError(error) {},
|
||||
|
||||
async saveAndSubmitWorkOrder() {
|
||||
// Work order submission after successful payment.
|
||||
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||
try {
|
||||
await submitWorkOrder({
|
||||
pageNameToLog: this.pageName,
|
||||
submitAfterSave: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(`error: response from submit work order: ${error.message}`);
|
||||
|
||||
// navigate to error page
|
||||
const errorPayload = {
|
||||
cause: `Error while submitting work order after Adyen payment.`,
|
||||
currentPage: this.pageName,
|
||||
sessionId: this.sessionId,
|
||||
idempotencyKey: this.idempotencyKey,
|
||||
};
|
||||
|
||||
this.$router.handleSoftError(errorPayload);
|
||||
}
|
||||
|
||||
// clear order
|
||||
await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_STATE);
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.pageName
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
adyenInitRequestInfo() {
|
||||
return {
|
||||
sourceSystem: this.sourceSystem,
|
||||
referralSequenceNumber: this.$store.getters.order.referralSequenceNumber,
|
||||
workOrderNumber: this.workOrderNumberLastSixDigits,
|
||||
zipCodeCtu: this.locationInfo.zipCodeCtu,
|
||||
amount: this.adyenPriceTotal,
|
||||
city: this.locationInfo.city,
|
||||
houseNumberOrName: this.splitStreetAddress.number,
|
||||
street: this.splitStreetAddress.street,
|
||||
zipCode: this.locationInfo.zipCode,
|
||||
stateOrProvince: this.locationInfo.state,
|
||||
returnUrl: applicationConfig.PIA_ADYEN_RETURN_URL,
|
||||
email: this.$store.getters.order.customer.emailAddress,
|
||||
IP: "127.0.0.1", // TODO
|
||||
firstName: this.$store.getters.order.customer.firstName,
|
||||
lastName: this.$store.getters.order.customer.lastName,
|
||||
idempotencyKey: this.idempotencyKey,
|
||||
};
|
||||
},
|
||||
|
||||
workOrderNumberLastSixDigits() {
|
||||
const workOrderNumber = this.$store.getters.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;
|
||||
},
|
||||
|
||||
locationInfo() {
|
||||
const serviceLocation = this.$store.getters.order.serviceLocation;
|
||||
const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE;
|
||||
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,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
splitStreetAddress() {
|
||||
const address = this.locationInfo.address;
|
||||
const tokens = address.split(" ") ?? [""];
|
||||
const number = tokens[0];
|
||||
|
||||
const street = tokens.slice(1).reduce((prev, next) => `${prev} ${next}`);
|
||||
|
||||
return {
|
||||
number: number ?? "",
|
||||
street: street ?? "",
|
||||
};
|
||||
},
|
||||
|
||||
idempotencyKey() {
|
||||
return `${this.$store.getters.order.referralCorrelationId}-${this.sourceSystem}`;
|
||||
},
|
||||
|
||||
sourceSystem() {
|
||||
return "FMG-2.0";
|
||||
},
|
||||
|
||||
amountDue() {
|
||||
return getAmountDue(this.$store.getters.order.lineItems);
|
||||
},
|
||||
|
||||
adyenPriceTotal() {
|
||||
return this.amountDue * 100;
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
Form,
|
||||
funnelHeader,
|
||||
funnelSubHeader,
|
||||
navbar,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -170,6 +170,7 @@ import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stas
|
|||
import { debugLog } from "@/helpers/debug-log-helper";
|
||||
import { ErrorMessage } from "vee-validate";
|
||||
import { Field } from "vee-validate";
|
||||
import experimentMixin from "../../mixins/experiment-mixin";
|
||||
|
||||
defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED));
|
||||
defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED));
|
||||
|
|
@ -609,10 +610,17 @@ export default {
|
|||
}
|
||||
|
||||
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_PAY_NOW,
|
||||
this.pageName
|
||||
|
||||
const shouldUseAdyen = experimentMixin.methods.hasSettingEqualTo(
|
||||
experimentSettings.USE_ADYEN_PAYMENT,
|
||||
"true"
|
||||
);
|
||||
|
||||
const scenarioName = shouldUseAdyen
|
||||
? this.navigationScenarios.CLICKED_PAY_NOW_ADYEN
|
||||
: this.navigationScenarios.CLICKED_PAY_NOW;
|
||||
|
||||
this.$router.navigateWithoutSaving(scenarioName, this.pageName);
|
||||
},
|
||||
async evaluatePromosAndTaxItemsOnOrder() {
|
||||
//Revalidate promos if there are any inactive, or active promos
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ export default {
|
|||
lastFour: lastFour,
|
||||
};
|
||||
|
||||
console.log(`CCToken =`);
|
||||
console.log(ccToken);
|
||||
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_CCTOKEN, ccToken, false);
|
||||
baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ const navigationScenarios = {
|
|||
// Payment
|
||||
CLICKED_INSURANCE: "CLICKED_INSURANCE",
|
||||
CLICKED_PAY_NOW: "CLICKED_PAY_NOW",
|
||||
CLICKED_PAY_NOW_ADYEN: "CLICKED_PAY_NOW_ADYEN",
|
||||
CLICKED_PAY_LATER: "CLICKED_PAY_LATER",
|
||||
PIA_ERROR: "PIA_ERROR",
|
||||
PIA_CC_ERROR: "PIA_CC_ERROR",
|
||||
|
|
|
|||
|
|
@ -89,6 +89,15 @@ export const routeData = {
|
|||
name: "payment-pia-return",
|
||||
path: "/payment-pia-return",
|
||||
},
|
||||
PAYMENT_ADYEN: {
|
||||
name: "payment-adyen",
|
||||
path: "/payment-adyen",
|
||||
},
|
||||
PAYMENT_ADYEN_RETURN: {
|
||||
name: "adyen-return",
|
||||
path: "/virtual/payment/return",
|
||||
virtual: true,
|
||||
},
|
||||
CONFIRMATION: {
|
||||
name: "confirmation",
|
||||
path: "/confirmation",
|
||||
|
|
|
|||
|
|
@ -537,6 +537,10 @@ const routingTable = function () {
|
|||
scenario: navigationScenarios.CLICKED_PAY_NOW,
|
||||
destinationPageData: routeData.PAYMENT,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.CLICKED_PAY_NOW_ADYEN,
|
||||
destinationPageData: routeData.PAYMENT_ADYEN,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.CLICKED_INSURANCE,
|
||||
destinationPageData: routeData.INSURANCE_COMPANY,
|
||||
|
|
@ -563,6 +567,19 @@ const routingTable = function () {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
pageName: routeData.PAYMENT_ADYEN.name,
|
||||
maps: [
|
||||
{
|
||||
scenario: navigationScenarios.CLICKED_BACK,
|
||||
destinationPageData: routeData.PAYMENT_METHOD,
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.CLICKED_FORWARD,
|
||||
destinationPageData: routeData.CONFIRMATION,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
pageName: routeData.PAYMENT_PIA_RETURN.name,
|
||||
maps: [
|
||||
|
|
|
|||
73
src/router/methods/route-logic/adyen-return.js
Normal file
73
src/router/methods/route-logic/adyen-return.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import { AdyenCheckout } from "@adyen/adyen-web";
|
||||
import { routeData } from "@/router/constants/routes";
|
||||
import { createAdyenCheckout, getSessionInfo } from "@/helpers/adyen-helper";
|
||||
|
||||
export async function adyenReturnBeforeEnter(to, from) {
|
||||
console.log(`In adyen return.`);
|
||||
console.log(JSON.parse(JSON.stringify(to)));
|
||||
|
||||
const sessionId = to?.query?.sessionId;
|
||||
const redirectResult = to?.query?.redirectResult;
|
||||
|
||||
if (sessionId && redirectResult) {
|
||||
const result = await finalizeAdyenPayment(sessionId, redirectResult);
|
||||
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.
|
||||
|
||||
return {
|
||||
name: routeData.CONFIRMATION.name,
|
||||
replace: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
name: routeData.ERROR.name,
|
||||
replace: true,
|
||||
};
|
||||
}
|
||||
|
||||
function finalizeAdyenPayment(sessionId, redirectResult) {
|
||||
return new Promise((resolve, reject) => {
|
||||
createAdyenCheckout({
|
||||
session: {
|
||||
id: sessionId,
|
||||
},
|
||||
handlers: {
|
||||
onPaymentCompleted: (result, component) => {
|
||||
console.log(`Payment successful`);
|
||||
console.log(result);
|
||||
resolve(result);
|
||||
},
|
||||
onPaymentFailed: (result, component) => {
|
||||
console.log(`Payment failed`);
|
||||
console.log(result);
|
||||
reject("Payment failed from Adyen");
|
||||
},
|
||||
onError: (error, component) => {
|
||||
console.log(`Error occured`);
|
||||
console.log(error);
|
||||
reject("Error from Adyen");
|
||||
},
|
||||
},
|
||||
options: {},
|
||||
}).then(
|
||||
(checkout) => {
|
||||
checkout.submitDetails({
|
||||
details: {
|
||||
redirectResult: redirectResult,
|
||||
},
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import { restartBeforeEnter } from "@/router/methods/route-logic/restart";
|
|||
import { paymentMethodBeforeEnter } from "@/router/methods/route-logic/payment-method";
|
||||
import { paymentBeforeEnter } from "@/router/methods/route-logic/payment";
|
||||
import { serviceLocationBeforeEnter } from "@/router/methods/route-logic/service-location";
|
||||
import { adyenReturnBeforeEnter } from "@/router/methods/route-logic/adyen-return";
|
||||
|
||||
export const routes = [
|
||||
// Non-virtual pages.
|
||||
|
|
@ -36,6 +37,7 @@ export const routes = [
|
|||
createRoute(routeData.PAYMENT_METHOD, paymentMethodBeforeEnter),
|
||||
createRoute(routeData.PAYMENT, paymentBeforeEnter),
|
||||
createRoute(routeData.PAYMENT_PIA_RETURN),
|
||||
createRoute(routeData.PAYMENT_ADYEN),
|
||||
createRoute(routeData.CONFIRMATION),
|
||||
createRoute(routeData.RETURN_USER),
|
||||
createRoute(routeData.MOBILE_DETAILS),
|
||||
|
|
@ -47,4 +49,5 @@ export const routes = [
|
|||
createVirtualRoute(routeData.AUTO_ROUTE, autoRouteBeforeEnter),
|
||||
createVirtualRoute(routeData.ERROR, errorBeforeEnter),
|
||||
createVirtualRoute(routeData.RESTART, restartBeforeEnter),
|
||||
createVirtualRoute(routeData.PAYMENT_ADYEN_RETURN, adyenReturnBeforeEnter),
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in a new issue