Merge branch 'develop' into rslmerge/2026.01.08-to-develop
This commit is contained in:
commit
7fd8f8ef76
33 changed files with 1085 additions and 133 deletions
|
|
@ -13,6 +13,8 @@ const environmentVariables = {
|
||||||
['__VUE_APP_SAFELITE_HOP__']: "https://sv2-safelitehop-dev.safelite.com/fmgCheckoutShared.aspx",
|
['__VUE_APP_SAFELITE_HOP__']: "https://sv2-safelitehop-dev.safelite.com/fmgCheckoutShared.aspx",
|
||||||
['__VUE_APP_SESSION_TIMEOUT_MINUTES__']: 30,
|
['__VUE_APP_SESSION_TIMEOUT_MINUTES__']: 30,
|
||||||
['__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__']: "",
|
['__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__']: "",
|
||||||
|
['__VUE_APP_ADYEN_ENVIRONMENT__']: "test",
|
||||||
|
['__VUE_APP_ADYEN_CLIENT_KEY__']: "test_WYGT4F5ZT5BRRL5MPWHK6QLYOIXZXROD",
|
||||||
};
|
};
|
||||||
|
|
||||||
const keysOnly = Object.keys(environmentVariables);
|
const keysOnly = Object.keys(environmentVariables);
|
||||||
|
|
|
||||||
41
package-lock.json
generated
41
package-lock.json
generated
|
|
@ -8,6 +8,7 @@
|
||||||
"name": "Safelite",
|
"name": "Safelite",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@adyen/adyen-web": "^6.27.0",
|
||||||
"@iframe-resizer/child": "^5.3.3",
|
"@iframe-resizer/child": "^5.3.3",
|
||||||
"axios": "^0.30.2",
|
"axios": "^0.30.2",
|
||||||
"bootstrap": "^5.3.3",
|
"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": "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": {
|
"node_modules/@ampproject/remapping": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||||
|
|
@ -3173,6 +3186,12 @@
|
||||||
"node": ">=10.13.0"
|
"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": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||||
|
|
@ -3328,6 +3347,12 @@
|
||||||
"@types/send": "*"
|
"@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": {
|
"node_modules/@types/graceful-fs": {
|
||||||
"version": "4.1.9",
|
"version": "4.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
|
||||||
|
|
@ -5789,6 +5814,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/clean-css": {
|
||||||
"version": "5.3.3",
|
"version": "5.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
|
||||||
|
|
@ -13681,6 +13712,16 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@adyen/adyen-web": "^6.27.0",
|
||||||
"@iframe-resizer/child": "^5.3.3",
|
"@iframe-resizer/child": "^5.3.3",
|
||||||
"axios": "^0.30.2",
|
"axios": "^0.30.2",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ export class HomePage extends BasePage {
|
||||||
|
|
||||||
//Zip Entry
|
//Zip Entry
|
||||||
this.enterServiceZipTextBox = this.page.locator('#zipCodeTextbox');
|
this.enterServiceZipTextBox = this.page.locator('#zipCodeTextbox');
|
||||||
this.zipEntryLetsGetStartedButton = this.page.locator('#zipCodeTextboxButton');
|
this.zipEntryLetsGetStartedButton = this.page.locator('#zipCodeTextbox');
|
||||||
this.getQuoteAndScheduleButton = this.page.getByLabel('main').getByRole('link', { name: 'Get quote + schedule' });
|
this.getQuoteAndScheduleButton = this.page.getByLabel('main').getByRole('link', { name: 'Get quote + schedule' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,10 +61,11 @@ export class HomePage extends BasePage {
|
||||||
|
|
||||||
async letsGetStarted(zip: string, enterFunnelWithZip: boolean) {
|
async letsGetStarted(zip: string, enterFunnelWithZip: boolean) {
|
||||||
if (enterFunnelWithZip) {
|
if (enterFunnelWithZip) {
|
||||||
await this.letsGetStartedButton.evaluate((element, zip) => {
|
await this.zipEntryLetsGetStartedButton.fill(zip);
|
||||||
|
/* await this.letsGetStartedButton.evaluate((element, zip) => {
|
||||||
const currentHref = element.getAttribute('href') || '';
|
const currentHref = element.getAttribute('href') || '';
|
||||||
element.setAttribute('href', `${currentHref}&zipCode=${zip}`);
|
element.setAttribute('href', `${currentHref}?zipCode=${zip}`);
|
||||||
}, zip);
|
}, zip);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until modal pop up opens and close pop up
|
// Wait until modal pop up opens and close pop up
|
||||||
|
|
|
||||||
|
|
@ -81,9 +81,9 @@ export class LookupPage extends BasePage {
|
||||||
|
|
||||||
// Map of expected messages by lookup type
|
// Map of expected messages by lookup type
|
||||||
const expectedMessages = {
|
const expectedMessages = {
|
||||||
'address': "Your address didn't return a VIN match.Please re-enter the information below or provide your VIN in a different way.",
|
'address': "Your address didn't return a VIN match.Please re-enter the information below or provide your VIN in a different way.",
|
||||||
'license plate': "Your license plate didn’t return a VIN match.Please re-enter the information above or provide your VIN in a different way.",
|
'license plate': "Your license plate didn’t return a VIN match.Please re-enter the information above or provide your VIN in a different way.",
|
||||||
'VIN': "Your VIN didn’t return a vehicle matchPlease re-enter your VIN or we can look up your VIN for you.",
|
'VIN': "Your VIN didn’t return a vehicle matchPlease re-enter your VIN or we can look up your VIN for you.",
|
||||||
'ZIP code': "Your ZIP code didn't return a match.Please re-enter the information above or provide your VIN in a different way."
|
'ZIP code': "Your ZIP code didn't return a match.Please re-enter the information above or provide your VIN in a different way."
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -106,19 +106,19 @@ export class LookupPage extends BasePage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleZipValidation(testData: Partial<ITestData>, zip: string, lookupType: VehicleLookupType, alertFlags?: IAlertFlags): Promise<boolean> {
|
async handleZipValidation(testData: Partial<ITestData>): Promise<boolean> {
|
||||||
|
|
||||||
let { vehicleDamage } = testData;
|
let { customerDetails,vehicleDamage, vehicleDetails, alertFlags } = testData;
|
||||||
// Only proceed with validation if alertFlags is provided
|
// Only proceed with validation if alertFlags is provided
|
||||||
if (alertFlags) {
|
if (alertFlags) {
|
||||||
if (alertFlags.isUnserviceableZip) {
|
if (alertFlags.isUnserviceableZip) {
|
||||||
await this.checkForUnserviceableZipAlertMessage(zip);
|
await this.checkForUnserviceableZipAlertMessage(customerDetails!.address.postalCode!);
|
||||||
throw new TestSuccessAlert('Unserviceable ZIP validation successful.');
|
throw new TestSuccessAlert('Unserviceable ZIP validation successful.');
|
||||||
} else if (alertFlags.isInvalidZip) {
|
} else if (alertFlags.isInvalidZip) {
|
||||||
await this.checkForInvalidZipAlertMessage();
|
await this.checkForInvalidZipAlertMessage();
|
||||||
throw new TestSuccessAlert('Invalid ZIP validation successful.');
|
throw new TestSuccessAlert('Invalid ZIP validation successful.');
|
||||||
} else if (alertFlags.isVinNotFound) {
|
} else if (alertFlags.isVinNotFound) {
|
||||||
await this.checkForVinNotFoundAlertMessage(lookupType);
|
await this.checkForVinNotFoundAlertMessage(vehicleDetails!.vehicleLookupType!);
|
||||||
throw new TestSuccessAlert('Vin not found validation successful.');
|
throw new TestSuccessAlert('Vin not found validation successful.');
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ export class PaypalPage extends BasePage {
|
||||||
await this.paypalLoginButton.click();
|
await this.paypalLoginButton.click();
|
||||||
await this.completePurchaseButton.click();
|
await this.completePurchaseButton.click();
|
||||||
} else {
|
} else {
|
||||||
|
await this.usernameTextBox.waitFor({ state: 'visible' });
|
||||||
|
await this.page.screenshot({ path: `test-results\\ortoni-data\\paypal-username-${Date.now()}.png`, fullPage: true });
|
||||||
await this.usernameTextBox.fill(paymentDetails.username!);
|
await this.usernameTextBox.fill(paymentDetails.username!);
|
||||||
await this.nextButton.click();
|
await this.nextButton.click();
|
||||||
await this.tryAnotherWayButton.click();
|
await this.tryAnotherWayButton.click();
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ export class SchedulePage extends BasePage {
|
||||||
readonly timeSlots: Locator;
|
readonly timeSlots: Locator;
|
||||||
readonly allDayDropOffButton: Locator;
|
readonly allDayDropOffButton: Locator;
|
||||||
readonly pickATimeButton: Locator;
|
readonly pickATimeButton: Locator;
|
||||||
|
readonly mobileFirstModalCloseButton: Locator;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
super(page);
|
super(page);
|
||||||
|
|
@ -65,6 +66,7 @@ export class SchedulePage extends BasePage {
|
||||||
this.viewMoreDatesLink = this.page.getByText(/View more dates/).first();
|
this.viewMoreDatesLink = this.page.getByText(/View more dates/).first();
|
||||||
this.appointmentDuration = this.page.locator('.duration-text-block');
|
this.appointmentDuration = this.page.locator('.duration-text-block');
|
||||||
this.timeSlots = this.page.locator('fieldset:has(>legend#chooseTimeSlot) label').filter({ visible: true});
|
this.timeSlots = this.page.locator('fieldset:has(>legend#chooseTimeSlot) label').filter({ visible: true});
|
||||||
|
this.mobileFirstModalCloseButton = this.page.getByRole('dialog').getByRole('button', { name: 'Close' });
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectLocation(testData: Partial<ITestData>) {
|
async selectLocation(testData: Partial<ITestData>) {
|
||||||
|
|
@ -229,6 +231,9 @@ export class SchedulePage extends BasePage {
|
||||||
async handleSchedulePage(testData: Partial<ITestData>) {
|
async handleSchedulePage(testData: Partial<ITestData>) {
|
||||||
const { appointmentDetails } = testData;
|
const { appointmentDetails } = testData;
|
||||||
await this.validateProgressBar(ProgressBarPercentages.SchedulePage);
|
await this.validateProgressBar(ProgressBarPercentages.SchedulePage);
|
||||||
|
if (await this.mobileFirstModalCloseButton.isVisible()) {
|
||||||
|
await this.mobileFirstModalCloseButton.click();
|
||||||
|
}
|
||||||
await this.selectLocation(testData);
|
await this.selectLocation(testData);
|
||||||
await this.scheduleFirstAppointment(testData);
|
await this.scheduleFirstAppointment(testData);
|
||||||
await this.nextPage();
|
await this.nextPage();
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ export class ServiceZipPage extends LookupPage {
|
||||||
|
|
||||||
@step("ZipLookupPage >> Lookup by service ZIP: ")
|
@step("ZipLookupPage >> Lookup by service ZIP: ")
|
||||||
async handleServiceZipPage(testData: Partial<ITestData>) {
|
async handleServiceZipPage(testData: Partial<ITestData>) {
|
||||||
const { customerDetails, vehicleDetails, alertFlags } = testData;
|
const { customerDetails } = testData;
|
||||||
await this.validateProgressBar(ProgressBarPercentages.ServiceZipPage);
|
await this.validateProgressBar(ProgressBarPercentages.ServiceZipPage);
|
||||||
await this.enterZip(customerDetails!.address.postalCode!);
|
await this.enterZip(customerDetails!.address.postalCode!);
|
||||||
await this.handleZipValidation(testData, customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
|
await this.handleZipValidation(testData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,10 +29,10 @@ export class VehicleLookupAddressPage extends LookupPage {
|
||||||
|
|
||||||
@step("VehicleLookupAddressPage >> Lookup by address: ")
|
@step("VehicleLookupAddressPage >> Lookup by address: ")
|
||||||
async handleVehicleLookupAddressPage(testData: Partial<ITestData>) {
|
async handleVehicleLookupAddressPage(testData: Partial<ITestData>) {
|
||||||
const { customerDetails, vehicleDetails, alertFlags } = testData;
|
const { customerDetails, vehicleDetails } = testData;
|
||||||
|
|
||||||
await this.validateProgressBar(ProgressBarPercentages.VehicleLookupAddressPage);
|
await this.validateProgressBar(ProgressBarPercentages.VehicleLookupAddressPage);
|
||||||
await this.lookupVehicleByAddress(customerDetails!, vehicleDetails!);
|
await this.lookupVehicleByAddress(customerDetails!, vehicleDetails!);
|
||||||
await this.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
|
await this.handleZipValidation(testData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -34,11 +34,11 @@ export class VehicleLookupLicensePage extends LookupPage {
|
||||||
|
|
||||||
@step("VehicleLookupLicensePage >> Lookup by license plate: ")
|
@step("VehicleLookupLicensePage >> Lookup by license plate: ")
|
||||||
async handleVehicleLookupLicensePage(testData: Partial<ITestData>) {
|
async handleVehicleLookupLicensePage(testData: Partial<ITestData>) {
|
||||||
const { customerDetails, vehicleDetails, alertFlags } = testData;
|
const { customerDetails, vehicleDetails } = testData;
|
||||||
|
|
||||||
await this.validateProgressBar(ProgressBarPercentages.VehicleLookupLicensePage);
|
await this.validateProgressBar(ProgressBarPercentages.VehicleLookupLicensePage);
|
||||||
await this.enterPlateDetails(vehicleDetails!);
|
await this.enterPlateDetails(vehicleDetails!);
|
||||||
await this.enterZip(customerDetails!.address.postalCode!);
|
await this.enterZip(customerDetails!.address.postalCode!);
|
||||||
await this.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
|
await this.handleZipValidation(testData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -24,11 +24,11 @@ export class VinLookupPage extends LookupPage {
|
||||||
|
|
||||||
@step("VinLookupPage >> Lookup by VIN: ")
|
@step("VinLookupPage >> Lookup by VIN: ")
|
||||||
async handleVehicleLookupVinPage(testData: Partial<ITestData>) {
|
async handleVehicleLookupVinPage(testData: Partial<ITestData>) {
|
||||||
const { customerDetails, vehicleDetails, alertFlags } = testData;
|
const { customerDetails, vehicleDetails } = testData;
|
||||||
let vin: string;
|
let vin: string;
|
||||||
|
|
||||||
if (Array.isArray(vehicleDetails?.vin)) {
|
if (Array.isArray(vehicleDetails?.vin)) {
|
||||||
vin = vehicleDetails.vin[0];
|
vin = vehicleDetails!.vin[0];
|
||||||
} else {
|
} else {
|
||||||
vin = vehicleDetails?.vin || '';
|
vin = vehicleDetails?.vin || '';
|
||||||
}
|
}
|
||||||
|
|
@ -36,6 +36,6 @@ export class VinLookupPage extends LookupPage {
|
||||||
await this.validateProgressBar(ProgressBarPercentages.VinLookupPage);
|
await this.validateProgressBar(ProgressBarPercentages.VinLookupPage);
|
||||||
await this.enterVin(vin);
|
await this.enterVin(vin);
|
||||||
await this.enterZip(customerDetails!.address.postalCode!);
|
await this.enterZip(customerDetails!.address.postalCode!);
|
||||||
await this.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!);
|
await this.handleZipValidation(testData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +57,7 @@ export class AddressForm extends BasePage {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.page.hover(".pac-container .pac-item");
|
await this.addressSuggestionList.hover();
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
await this.addressSuggestionList.click(); // Select the first suggestion
|
await this.addressSuggestionList.click(); // Select the first suggestion
|
||||||
//await this.streetAddressTextBox.press('Tab'); // Move focus to ZIP code field
|
//await this.streetAddressTextBox.press('Tab'); // Move focus to ZIP code field
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//Imports here
|
//Imports here
|
||||||
import { ITestData } from 'framework/TestData'
|
import { ITestData } from 'framework/TestData'
|
||||||
import { ServiceLocation, PaymentType } from 'safelite-playwright-core';
|
import { ServiceLocation, ServicePackage, PaymentType } from 'safelite-playwright-core';
|
||||||
import { ITestCase } from '../framework/Typedefs'
|
import { ITestCase } from '../framework/Typedefs'
|
||||||
import { VehicleLookupType } from 'safelite-playwright-core';
|
import { VehicleLookupType } from 'safelite-playwright-core';
|
||||||
import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core';
|
import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core';
|
||||||
|
|
@ -29,7 +29,8 @@ const cashReplaceDynamicRecalMobileData: Partial<ITestData> = {
|
||||||
postalCode: '21237'
|
postalCode: '21237'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
servicePackage: ServicePackage.Premium,
|
||||||
// Override vehicle details
|
// Override vehicle details
|
||||||
vehicleDetails: {
|
vehicleDetails: {
|
||||||
...getDefaultTestData().vehicleDetails!,
|
...getDefaultTestData().vehicleDetails!,
|
||||||
|
|
@ -59,7 +60,8 @@ const cashReplaceDynamicRecalMobileData: Partial<ITestData> = {
|
||||||
|
|
||||||
// Override payment details
|
// Override payment details
|
||||||
paymentDetails: {
|
paymentDetails: {
|
||||||
paymentType: PaymentType.PayAtService
|
paymentType: PaymentType.PayAtService,
|
||||||
|
promoCode: 'digitalrain'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ const cashReplaceMultiSlidingGlassDropoffData: Partial<ITestData> = {
|
||||||
appointmentDetails: {
|
appointmentDetails: {
|
||||||
serviceLocation: ServiceLocation.DropOff,
|
serviceLocation: ServiceLocation.DropOff,
|
||||||
appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate,
|
appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate,
|
||||||
shopAddress: "6826 sawmill rd, Columbus, OH 43235"
|
shopAddress: "1343 cameron ave, lewis center, oh 43035"
|
||||||
},
|
},
|
||||||
|
|
||||||
// Override vehicle details
|
// Override vehicle details
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,10 @@ const lookupTypesToTest: LookupTestCase[] = [
|
||||||
},
|
},
|
||||||
customerDetails: {
|
customerDetails: {
|
||||||
address: {
|
address: {
|
||||||
street: '4076 Spectacle Drive',
|
street: '4219 Turpin Ln',
|
||||||
city: 'Columbus',
|
city: 'Columbus',
|
||||||
state: 'OH',
|
state: 'OH',
|
||||||
postalCode: '59261',
|
postalCode: '43230',
|
||||||
country: 'United States'
|
country: 'United States'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ const applicationConfig = {
|
||||||
PIA_ERROR_URL:
|
PIA_ERROR_URL:
|
||||||
location.protocol + "//" + location.host + "/fmg/payment-pia-return?src=concept-funnel",
|
location.protocol + "//" + location.host + "/fmg/payment-pia-return?src=concept-funnel",
|
||||||
CONFIRMATION_URL: location.protocol + "//" + location.host + "/fmg/confirmation",
|
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",
|
GOOGLE_CALENDAR: "https://www.google.com/calendar/render?action=TEMPLATE",
|
||||||
YAHOO_CALENDAR: "https://calendar.yahoo.com/?v=60",
|
YAHOO_CALENDAR: "https://calendar.yahoo.com/?v=60",
|
||||||
OUTLOOK_CALENDAR:
|
OUTLOOK_CALENDAR:
|
||||||
|
|
@ -31,6 +32,8 @@ const applicationConfig = {
|
||||||
COOKIE_NAME_LENGTH_MAX_LIMIT: 44,
|
COOKIE_NAME_LENGTH_MAX_LIMIT: 44,
|
||||||
SESSION_TIMEOUT_MINUTES: process.env.__VUE_APP_SESSION_TIMEOUT_MINUTES__,
|
SESSION_TIMEOUT_MINUTES: process.env.__VUE_APP_SESSION_TIMEOUT_MINUTES__,
|
||||||
RETURN_USER_PAGE: "/fmg/return-user",
|
RETURN_USER_PAGE: "/fmg/return-user",
|
||||||
|
ADYEN_CLIENT_KEY: process.env.__VUE_APP_ADYEN_CLIENT_KEY__,
|
||||||
|
ADYEN_ENVIRONMENT: process.env.__VUE_APP_ADYEN_ENVIRONMENT__,
|
||||||
};
|
};
|
||||||
|
|
||||||
export { applicationConfig };
|
export { applicationConfig };
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,14 @@ const endpoints = {
|
||||||
url: "/parts/api/v1/parts/oem-after-market-parts",
|
url: "/parts/api/v1/parts/oem-after-market-parts",
|
||||||
method: "POST",
|
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 };
|
export { endpoints };
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ const experimentSettings = {
|
||||||
SHOW_NO_PM_MOBILE_DAYS: "Show_NoPMmobileDays",
|
SHOW_NO_PM_MOBILE_DAYS: "Show_NoPMmobileDays",
|
||||||
SHOW_NO_MOBILE_AVAILABLE_DAYS: "Show_NoMobileAvailableDays",
|
SHOW_NO_MOBILE_AVAILABLE_DAYS: "Show_NoMobileAvailableDays",
|
||||||
OFFER_OEM: "OfferOem",
|
OFFER_OEM: "OfferOem",
|
||||||
|
USE_ADYEN_PAYMENT: "UseAdyenPayment",
|
||||||
};
|
};
|
||||||
|
|
||||||
const experimentTriggers = {
|
const experimentTriggers = {
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,10 @@ export const pageProgressMapper = {
|
||||||
percent: 98.5,
|
percent: 98.5,
|
||||||
step: 4,
|
step: 4,
|
||||||
},
|
},
|
||||||
|
"payment-adyen": {
|
||||||
|
percent: 98.5,
|
||||||
|
step: 4,
|
||||||
|
},
|
||||||
confirmation: {
|
confirmation: {
|
||||||
percent: 100,
|
percent: 100,
|
||||||
step: 4,
|
step: 4,
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ export default {
|
||||||
if (event.screenX === 0 && event.screenY === 0) {
|
if (event.screenX === 0 && event.screenY === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$emit("date-clicked", date);
|
this.$emit("date-selected", date);
|
||||||
},
|
},
|
||||||
getWeekStartDate(dateString) {
|
getWeekStartDate(dateString) {
|
||||||
const date = convertDateStringToDate(dateString);
|
const date = convertDateStringToDate(dateString);
|
||||||
|
|
@ -846,12 +846,6 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
isLoading(newValue) {
|
|
||||||
// if done loading dates, then set to first available date
|
|
||||||
if (newValue === false && this.firstAvailableSelectableDate) {
|
|
||||||
this.selectedDate = this.firstAvailableSelectableDate;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modelValue(newValue) {
|
modelValue(newValue) {
|
||||||
this.resetField({
|
this.resetField({
|
||||||
value: newValue,
|
value: newValue,
|
||||||
|
|
|
||||||
153
src/helpers/adyen-helper.js
Normal file
153
src/helpers/adyen-helper.js
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
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";
|
||||||
|
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 = 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: 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 mapAdyenToFmgPaymentMethod(adyenMethod) {
|
||||||
|
const paymentMethodMap = {
|
||||||
|
["scheme"]: paymentMethods.CREDIT_CARD,
|
||||||
|
["afterpaytouch"]: paymentMethods.AFTERPAY,
|
||||||
|
["paypal"]: paymentMethods.PAYPAL,
|
||||||
|
["applepay"]: paymentMethods.APPLE_PAY,
|
||||||
|
};
|
||||||
|
|
||||||
|
const match = paymentMethodMap[adyenMethod];
|
||||||
|
|
||||||
|
return match ?? paymentMethods.CREDIT_CARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateCcToken(adyenSessionInfo) {
|
||||||
|
const order = store.getters.order;
|
||||||
|
const locationInfo = getLocationInfo(order);
|
||||||
|
|
||||||
|
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;
|
||||||
|
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";
|
||||||
|
}
|
||||||
611
src/layouts/payment-adyen/payment-adyen.vue
Normal file
611
src/layouts/payment-adyen/payment-adyen.vue
Normal file
|
|
@ -0,0 +1,611 @@
|
||||||
|
<template>
|
||||||
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
||||||
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div id="card-container">
|
||||||
|
<div id="payment-container">
|
||||||
|
<funnelSubHeader class="py-5" cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
|
<div id="adyen-container"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="cart-container">
|
||||||
|
<cart
|
||||||
|
ref="cart"
|
||||||
|
:damage="damageInfo"
|
||||||
|
:availableVaps="[]"
|
||||||
|
:allowItemRemoval="false"
|
||||||
|
v-model="lineItems"
|
||||||
|
servicePackageOptionsCmsName="ServicePackageTitle"
|
||||||
|
recyclingModalCmsWidgetName="RecycleModal"
|
||||||
|
:isInsurance="isInsurance"
|
||||||
|
:insuranceDeductible="currentDeductible"
|
||||||
|
:insuranceCompanyName="insuranceCompanyName"
|
||||||
|
:showInsuranceCoverageAs="showInsuranceCoverageAs"
|
||||||
|
:isItac="isItac"
|
||||||
|
:isNoComp="isNoComp"
|
||||||
|
:isCollapsible="false" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<navbar
|
||||||
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
|
ref="navbar"
|
||||||
|
isForwardActionDisabled="true"
|
||||||
|
isSubmitHidden="true"
|
||||||
|
@back-clicked="backButtonAction" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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 { createAdyenCheckout } from "@/helpers/adyen-helper";
|
||||||
|
import { Dropin } from "@adyen/adyen-web/auto";
|
||||||
|
import { applicationConfig } from "@/constants/application-config";
|
||||||
|
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||||
|
|
||||||
|
import "@adyen/adyen-web/styles/adyen.css";
|
||||||
|
import { mapAdyenToFmgPaymentMethod } from "../../helpers/adyen-helper";
|
||||||
|
import { showFmgLoadingModal } from "../../helpers/loading-modal-helper";
|
||||||
|
import cart from "@/fmg-components/cart/cart";
|
||||||
|
import { coverageStatus } from "@/constants/insurance";
|
||||||
|
import { deepClone } from "@/helpers/object-helper";
|
||||||
|
import store from "@/store";
|
||||||
|
import { debugLog } from "@/helpers/debug-log-helper.js";
|
||||||
|
|
||||||
|
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() {
|
||||||
|
// Service Location
|
||||||
|
const serviceLocation = store.getters.order.serviceLocation;
|
||||||
|
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;
|
||||||
|
|
||||||
|
const serviceLocationReqs =
|
||||||
|
(isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs);
|
||||||
|
|
||||||
|
// Insurance
|
||||||
|
const isInsuranceSet = store.getters.order.payment.isInsurance !== null;
|
||||||
|
|
||||||
|
// Schedule
|
||||||
|
const schedule = store.getters.order.schedule;
|
||||||
|
const scheduleReqs = !!(
|
||||||
|
schedule.date &&
|
||||||
|
schedule.startTime &&
|
||||||
|
schedule.endTime &&
|
||||||
|
schedule.jobMaxMinutes &&
|
||||||
|
schedule.jobMinMinutes
|
||||||
|
);
|
||||||
|
|
||||||
|
// Customer
|
||||||
|
const customer = store.getters.order.customer;
|
||||||
|
const customerReqs = !!(
|
||||||
|
customer.firstName &&
|
||||||
|
customer.lastName &&
|
||||||
|
customer.phoneNumber &&
|
||||||
|
customer.emailAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
const paymentMethodReqs =
|
||||||
|
store.getters.order.payment.isPia !== null &&
|
||||||
|
(store.getters.order.payment.isPia || !!store.getters.order.payment.piaType);
|
||||||
|
|
||||||
|
const preReqResult =
|
||||||
|
serviceLocationReqs &&
|
||||||
|
isInsuranceSet &&
|
||||||
|
scheduleReqs &&
|
||||||
|
customerReqs &&
|
||||||
|
paymentMethodReqs;
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
{
|
||||||
|
debugLog("--- payment-adyen.vue pagePrereqs start ---", null, !preReqResult);
|
||||||
|
debugLog("mobileReqs:", mobileReqs, !preReqResult);
|
||||||
|
debugLog("serviceLocation.address:", serviceLocation.address, !preReqResult);
|
||||||
|
debugLog("serviceLocation.city:", serviceLocation.city, !preReqResult);
|
||||||
|
debugLog("serviceLocation.state:", serviceLocation.state, !preReqResult);
|
||||||
|
debugLog("serviceLocation.zipCode:", serviceLocation.zipCode, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("", null, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("dropOffInshopReqs:", dropOffInshopReqs, !preReqResult);
|
||||||
|
debugLog("serviceLocationReqs:", serviceLocationReqs, !preReqResult);
|
||||||
|
debugLog("providerLocation.streetAddress:", providerLocation.streetAddress, !preReqResult);
|
||||||
|
debugLog("providerLocation.city:", providerLocation.city, !preReqResult);
|
||||||
|
debugLog("providerLocation.state:", providerLocation.state, !preReqResult);
|
||||||
|
debugLog("providerLocation.zipCode:", providerLocation.zipCode, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("", null, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("isInsuranceSet:", isInsuranceSet, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("", null, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("scheduleReqs:", scheduleReqs, !preReqResult);
|
||||||
|
debugLog("schedule.date:", schedule.date, !preReqResult);
|
||||||
|
debugLog("schedule.startTime:", schedule.startTime, !preReqResult);
|
||||||
|
debugLog("schedule.endTime:", schedule.endTime, !preReqResult);
|
||||||
|
debugLog("schedule.jobMaxMinutes:", schedule.jobMaxMinutes, !preReqResult);
|
||||||
|
debugLog("schedule.jobMinMinutes:", schedule.jobMinMinutes, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("", null, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("customerReqs:", customerReqs, !preReqResult);
|
||||||
|
debugLog("customer.firstName:", customer.firstName, !preReqResult);
|
||||||
|
debugLog("customer.lastName:", customer.lastName, !preReqResult);
|
||||||
|
debugLog("customer.phoneNumber:", customer.phoneNumber, !preReqResult);
|
||||||
|
debugLog("customer.emailAddress:", customer.emailAddress, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("", null, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("paymentMethodReqs:", paymentMethodReqs, !preReqResult);
|
||||||
|
debugLog("store.getters.order.payment.isPia:", store.getters.order?.payment?.isPia, !preReqResult);
|
||||||
|
debugLog("store.getters.order.payment.piaType:", store.getters.order?.payment?.piaType, !preReqResult);
|
||||||
|
|
||||||
|
debugLog("--- payment-adyen.vue pagePrereqs end ---", null, !preReqResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return preReqResult;
|
||||||
|
},
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
const dropin = new Dropin(checkout, {
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).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);
|
||||||
|
|
||||||
|
showFmgLoadingModal(true);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
const paymentMethodFromSession = responseJson?.paymentMethod;
|
||||||
|
|
||||||
|
const paymentMethod = mapAdyenToFmgPaymentMethod(paymentMethodFromSession);
|
||||||
|
|
||||||
|
// Save payment type.
|
||||||
|
// For now, CC.
|
||||||
|
// Need to determine payment type from Adyen response
|
||||||
|
await this.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
||||||
|
paymentMethod,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
if (paymentMethod === paymentMethods.PAYPAL) {
|
||||||
|
await baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_PAYPAL_TOKEN,
|
||||||
|
responseJson?.storedToken,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Cart info
|
||||||
|
damageInfo() {
|
||||||
|
return this.$store.getters.damage;
|
||||||
|
},
|
||||||
|
isInsurance() {
|
||||||
|
return this.$store.getters.payment.isInsurance;
|
||||||
|
},
|
||||||
|
isNoComp() {
|
||||||
|
return this.$store.getters.policy.isNoComp;
|
||||||
|
},
|
||||||
|
isItac() {
|
||||||
|
return this.$store.getters.policy.isItac;
|
||||||
|
},
|
||||||
|
showInsuranceCoverageAs() {
|
||||||
|
if (!this.isInsurance) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isNoComp || this.isItac) {
|
||||||
|
return coverageStatus.NOCOMP;
|
||||||
|
} else {
|
||||||
|
return this.$store.getters.payment.insuranceCoverage.coverageStatus;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentDeductible() {
|
||||||
|
return this.$store.getters.policy.currentDeductible;
|
||||||
|
},
|
||||||
|
insuranceCompanyName() {
|
||||||
|
return this.$store.getters.policy.insuranceCompanyName;
|
||||||
|
},
|
||||||
|
lineItems() {
|
||||||
|
return deepClone(this.$store.getters.lineItems);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.initializeAdyen();
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
Form,
|
||||||
|
funnelHeader,
|
||||||
|
funnelSubHeader,
|
||||||
|
navbar,
|
||||||
|
cart,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
#card-container {
|
||||||
|
display: flex;
|
||||||
|
& > #payment-container {
|
||||||
|
flex-basis: 55%;
|
||||||
|
margin-right: 9%;
|
||||||
|
}
|
||||||
|
& > #cart-container {
|
||||||
|
flex-basis: 36%;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-down(lg) {
|
||||||
|
flex-direction: column;
|
||||||
|
& > #payment-container {
|
||||||
|
flex-basis: auto;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
& > #cart-container {
|
||||||
|
flex-basis: auto;
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -170,6 +170,7 @@ import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stas
|
||||||
import { debugLog } from "@/helpers/debug-log-helper";
|
import { debugLog } from "@/helpers/debug-log-helper";
|
||||||
import { ErrorMessage } from "vee-validate";
|
import { ErrorMessage } from "vee-validate";
|
||||||
import { Field } from "vee-validate";
|
import { Field } from "vee-validate";
|
||||||
|
import experimentMixin from "../../mixins/experiment-mixin";
|
||||||
|
|
||||||
defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED));
|
defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED));
|
||||||
|
|
@ -609,10 +610,17 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||||
this.$router.navigateWithoutSaving(
|
|
||||||
this.navigationScenarios.CLICKED_PAY_NOW,
|
const shouldUseAdyen = experimentMixin.methods.hasSettingEqualTo(
|
||||||
this.pageName
|
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() {
|
async evaluatePromosAndTaxItemsOnOrder() {
|
||||||
//Revalidate promos if there are any inactive, or active promos
|
//Revalidate promos if there are any inactive, or active promos
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,9 @@ export default {
|
||||||
lastFour: lastFour,
|
lastFour: lastFour,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(`CCToken =`);
|
||||||
|
console.log(ccToken);
|
||||||
|
|
||||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_CCTOKEN, ccToken, false);
|
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_CCTOKEN, ccToken, false);
|
||||||
baseMixin.methods.dispatchStoreAction(
|
baseMixin.methods.dispatchStoreAction(
|
||||||
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
cmsWidgetName="ScheduleYourServiceWidget"
|
cmsWidgetName="ScheduleYourServiceWidget"
|
||||||
id="schedule-your-service" />
|
id="schedule-your-service" />
|
||||||
<appointmentTypeQuestion
|
<appointmentTypeQuestion
|
||||||
|
v-if="hasSelectableDatesLoaded"
|
||||||
v-model="appointmentTypeFromAppointmentTypeQuestion"
|
v-model="appointmentTypeFromAppointmentTypeQuestion"
|
||||||
v-show="isAppointmentTypeDisplayed"
|
v-show="isAppointmentTypeDisplayed"
|
||||||
:isServiceableMobile="isServiceableMobile"
|
:isServiceableMobile="isServiceableMobile"
|
||||||
|
|
@ -133,8 +134,6 @@
|
||||||
:isOvernightDropoff="isOvernightDropoff" />
|
:isOvernightDropoff="isOvernightDropoff" />
|
||||||
</div>
|
</div>
|
||||||
<datePicker
|
<datePicker
|
||||||
:currentZip="zipCode"
|
|
||||||
:currentProviderNumber="selectedProvider?.providerNumber"
|
|
||||||
v-show="appointmentType"
|
v-show="appointmentType"
|
||||||
customComponentId="dateQuestion"
|
customComponentId="dateQuestion"
|
||||||
selectableDatesSetting="custom"
|
selectableDatesSetting="custom"
|
||||||
|
|
@ -144,7 +143,7 @@
|
||||||
class="text-link-small"
|
class="text-link-small"
|
||||||
:getMoreDatesCallback="getMoreScheduleData"
|
:getMoreDatesCallback="getMoreScheduleData"
|
||||||
validationRules="date-required"
|
validationRules="date-required"
|
||||||
@date-clicked="handleDateClicked"
|
@date-selected="handleDateSelected"
|
||||||
:pricingByDayBasePrice="pricingByDayBasePrice"
|
:pricingByDayBasePrice="pricingByDayBasePrice"
|
||||||
:pricingByDayUpcharge="pricingByDayUpcharge"
|
:pricingByDayUpcharge="pricingByDayUpcharge"
|
||||||
:showPricingByDay="showPricingByDay"
|
:showPricingByDay="showPricingByDay"
|
||||||
|
|
@ -640,12 +639,12 @@ export default {
|
||||||
showTimeSlotQuestion() {
|
showTimeSlotQuestion() {
|
||||||
if (
|
if (
|
||||||
this.selectedDate &&
|
this.selectedDate &&
|
||||||
this.selectedDate.includes("mobile") &&
|
this.appointmentTypeFromAppointmentTypeQuestion &&
|
||||||
!this.isMobileSelected
|
this.timeSlotsForSelectedDate
|
||||||
) {
|
) {
|
||||||
this.setSelectedDateToFirstAvailable();
|
return true;
|
||||||
}
|
}
|
||||||
return this.selectedDate && this.appointmentTypeFromAppointmentTypeQuestion;
|
return false;
|
||||||
},
|
},
|
||||||
isMobileStaticRecalibrationApplicable() {
|
isMobileStaticRecalibrationApplicable() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -873,6 +872,13 @@ export default {
|
||||||
? this.$refs.mobileFirstModal?.getIsModalOpen()
|
? this.$refs.mobileFirstModal?.getIsModalOpen()
|
||||||
: false;
|
: false;
|
||||||
},
|
},
|
||||||
|
hasSelectableDatesLoaded() {
|
||||||
|
if (this.isMobileSelected) {
|
||||||
|
return this.selectableDatesMobile?.days?.length > 0;
|
||||||
|
} else {
|
||||||
|
return this.selectableDatesInshop?.days?.length > 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
splitCopyOnCMSPlaceHolder,
|
splitCopyOnCMSPlaceHolder,
|
||||||
|
|
@ -1134,29 +1140,6 @@ export default {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getTimeSlotInfo() {
|
|
||||||
// Get the current date
|
|
||||||
const currentDate = getTodayDate();
|
|
||||||
|
|
||||||
// Add 10 days to the current date
|
|
||||||
currentDate.setDate(currentDate.getDate() + 10);
|
|
||||||
|
|
||||||
// Format the date as yyyy-mm-dd
|
|
||||||
const year = currentDate.getFullYear();
|
|
||||||
const month = String(currentDate.getMonth() + 1).padStart(2, "0");
|
|
||||||
const day = String(currentDate.getDate()).padStart(2, "0");
|
|
||||||
|
|
||||||
const formattedDate = `${year}-${month}-${day}`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
date: formattedDate,
|
|
||||||
endTime: "12:00",
|
|
||||||
jobMaxMinutes: "180",
|
|
||||||
jobMinMinutes: "120",
|
|
||||||
routeCode: "3357I-03357-M-I*20988*AM",
|
|
||||||
startTime: "08:00",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
onShopSelected(shopQuestionPopUpData) {
|
onShopSelected(shopQuestionPopUpData) {
|
||||||
this.resetWaitlist();
|
this.resetWaitlist();
|
||||||
this.preSelectedDate = null;
|
this.preSelectedDate = null;
|
||||||
|
|
@ -1209,8 +1192,6 @@ export default {
|
||||||
async initializeDatePicker() {
|
async initializeDatePicker() {
|
||||||
this.isShowMobileFirstAppt && this.showLoadingModal();
|
this.isShowMobileFirstAppt && this.showLoadingModal();
|
||||||
|
|
||||||
this.selectedDate = null;
|
|
||||||
|
|
||||||
const includeMobileTimeSlots = this.isServiceableMobile;
|
const includeMobileTimeSlots = this.isServiceableMobile;
|
||||||
const includeInshopTimeSlots = this.isServiceableInshop || this.isServiceableDropoff;
|
const includeInshopTimeSlots = this.isServiceableInshop || this.isServiceableDropoff;
|
||||||
const datePickerInitialData = await this.$refs.datePicker.loadInitialData({
|
const datePickerInitialData = await this.$refs.datePicker.loadInitialData({
|
||||||
|
|
@ -1601,28 +1582,40 @@ export default {
|
||||||
handleWaitListRequested(value) {
|
handleWaitListRequested(value) {
|
||||||
this.waitListRequested = value;
|
this.waitListRequested = value;
|
||||||
},
|
},
|
||||||
handleDateClicked(date) {
|
handleDateSelected(date) {
|
||||||
// do something to mark this as upcharge day or not...
|
const previousDate = this.selectedDate;
|
||||||
if (date.isPricingByDayUpchargeDay) {
|
|
||||||
this.includePricingByDayUpcharge = true;
|
// check if date actually changed
|
||||||
} else {
|
if (previousDate !== date.dateString) {
|
||||||
this.includePricingByDayUpcharge = false;
|
this.selectedTimeSlotInfo = this.getEmptyTimeSlot();
|
||||||
|
this.updateFooterButtonText(this.selectedTimeSlotInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: REMOVE AS PART OF CASH-1634
|
||||||
|
// // do something to mark this as upcharge day or not...
|
||||||
|
// if (date.isPricingByDayUpchargeDay) {
|
||||||
|
// this.includePricingByDayUpcharge = true;
|
||||||
|
// } else {
|
||||||
|
// this.includePricingByDayUpcharge = false;
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
getEmptyTimeSlot() {
|
||||||
|
return {
|
||||||
|
timeSlot: {
|
||||||
|
date: null,
|
||||||
|
routeCode: null,
|
||||||
|
startTime: null,
|
||||||
|
endTime: null,
|
||||||
|
jobMaxMinutes: null,
|
||||||
|
jobMinMinutes: null,
|
||||||
|
},
|
||||||
|
isPremiumAppointment: null,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
updateTimeSlot(timeSlotObj) {
|
updateTimeSlot(timeSlotObj) {
|
||||||
if (!timeSlotObj?.routeCode) {
|
if (!timeSlotObj?.routeCode) {
|
||||||
this.appointmentType = AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF;
|
this.appointmentType = AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF;
|
||||||
this.selectedTimeSlotInfo = {
|
this.selectedTimeSlotInfo = this.getEmptyTimeSlot();
|
||||||
timeSlot: {
|
|
||||||
date: null,
|
|
||||||
routeCode: null,
|
|
||||||
startTime: null,
|
|
||||||
endTime: null,
|
|
||||||
jobMaxMinutes: null,
|
|
||||||
jobMinMinutes: null,
|
|
||||||
},
|
|
||||||
isPremiumAppointment: null,
|
|
||||||
};
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const timeSlot = this.timeSlotsForSelectedDate?.timeSlots?.find(
|
const timeSlot = this.timeSlotsForSelectedDate?.timeSlots?.find(
|
||||||
|
|
@ -1721,6 +1714,9 @@ export default {
|
||||||
},
|
},
|
||||||
handleAppointmentTypeChange(newAppointmentType) {
|
handleAppointmentTypeChange(newAppointmentType) {
|
||||||
this.updateFooterButtonText();
|
this.updateFooterButtonText();
|
||||||
|
// if time appointment type changes, clear any selected time slot
|
||||||
|
this.selectedTimeSlotInfo = this.getEmptyTimeSlot();
|
||||||
|
|
||||||
if (newAppointmentType === AppointmentTypeStrings.MOBILE) {
|
if (newAppointmentType === AppointmentTypeStrings.MOBILE) {
|
||||||
// Remember last shop selected if previous selection was inshop/dropoff
|
// Remember last shop selected if previous selection was inshop/dropoff
|
||||||
if (
|
if (
|
||||||
|
|
@ -1729,17 +1725,6 @@ export default {
|
||||||
AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF) &&
|
AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF) &&
|
||||||
this.selectedProvider
|
this.selectedProvider
|
||||||
) {
|
) {
|
||||||
this.selectedTimeSlotInfo = {
|
|
||||||
timeSlot: {
|
|
||||||
date: null,
|
|
||||||
routeCode: null,
|
|
||||||
startTime: null,
|
|
||||||
endTime: null,
|
|
||||||
jobMaxMinutes: null,
|
|
||||||
jobMinMinutes: null,
|
|
||||||
},
|
|
||||||
isPremiumAppointment: null,
|
|
||||||
};
|
|
||||||
this.lastSelectedInshopOrDropoffProvider = this.selectedProvider;
|
this.lastSelectedInshopOrDropoffProvider = this.selectedProvider;
|
||||||
}
|
}
|
||||||
this.appointmentType = AppointmentTypeStrings.MOBILE;
|
this.appointmentType = AppointmentTypeStrings.MOBILE;
|
||||||
|
|
@ -1766,8 +1751,8 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.appointmentType = null;
|
this.appointmentType = null;
|
||||||
}
|
}
|
||||||
this.setSelectedDateToFirstAvailable();
|
this.setSelectedDateToFirstAvailable(); // v-if on appointmentTypeQuestion ensures dates have been loaded by now
|
||||||
this.setDisplayWaitList();
|
this.setDisplayWaitList(); // v-if on appointmentTypeQuestion ensures dates have been loaded by now
|
||||||
},
|
},
|
||||||
setSelectedDateToFirstAvailable() {
|
setSelectedDateToFirstAvailable() {
|
||||||
this.selectedDate = this.getFirstAvailableDate();
|
this.selectedDate = this.getFirstAvailableDate();
|
||||||
|
|
@ -1899,35 +1884,9 @@ export default {
|
||||||
watch: {
|
watch: {
|
||||||
appointmentTypeFromAppointmentTypeQuestion: {
|
appointmentTypeFromAppointmentTypeQuestion: {
|
||||||
handler(newValue, oldValue) {
|
handler(newValue, oldValue) {
|
||||||
this.handleAppointmentTypeChange(newValue);
|
this.handleAppointmentTypeChange(newValue); // v-if on appointmentTypeQuestion ensures dates have been loaded by now
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
selectedDate(newValue, oldValue) {
|
|
||||||
// Clear time slot selection if date selected changes
|
|
||||||
const selectedDate = this.getSelectedDateFromStore();
|
|
||||||
if (oldValue && this.appointmentType === AppointmentTypeStrings.MOBILE) {
|
|
||||||
oldValue = `${oldValue}-mobile`;
|
|
||||||
}
|
|
||||||
const hasValueChanged = newValue !== oldValue;
|
|
||||||
const isDateDifferent = (newValue || oldValue) !== selectedDate;
|
|
||||||
|
|
||||||
if (hasValueChanged && isDateDifferent && !this.selectedMobileFirstAppointment) {
|
|
||||||
this.selectedTimeSlotInfo = {
|
|
||||||
timeSlot: {
|
|
||||||
date: null,
|
|
||||||
routeCode: null,
|
|
||||||
startTime: null,
|
|
||||||
endTime: null,
|
|
||||||
jobMaxMinutes: null,
|
|
||||||
jobMinMinutes: null,
|
|
||||||
},
|
|
||||||
isPremiumAppointment: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectedTimeSlotInfo(newValue) {
|
|
||||||
this.updateFooterButtonText(newValue);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
funnelHeader,
|
funnelHeader,
|
||||||
|
|
@ -1940,7 +1899,6 @@ export default {
|
||||||
textBlock,
|
textBlock,
|
||||||
timeSlotQuestion,
|
timeSlotQuestion,
|
||||||
mobileFirstModal,
|
mobileFirstModal,
|
||||||
|
|
||||||
alert,
|
alert,
|
||||||
serviceZipModalQuestion,
|
serviceZipModalQuestion,
|
||||||
appointmentTypeQuestion,
|
appointmentTypeQuestion,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="time-slots-question">
|
<div class="time-slots-question">
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
|
ref="chooseDropOffOrInshop"
|
||||||
v-if="isDropOffAppointmentAvailable"
|
v-if="isDropOffAppointmentAvailable"
|
||||||
v-model="selectedAnswerForDropOffOrInshop"
|
v-model="selectedAnswerForDropOffOrInshop"
|
||||||
@update:modelValue="dropOffSelectionChanged"
|
@update:modelValue="dropOffSelectionChanged"
|
||||||
|
|
@ -23,8 +24,9 @@
|
||||||
</div>
|
</div>
|
||||||
</buttonQuestion>
|
</buttonQuestion>
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
ref="buttonQuestion"
|
ref="chooseTimeSlot"
|
||||||
v-if="shouldDisplayTimeSlotQuestion"
|
v-if="displayTimeSlotQuestion"
|
||||||
|
v-model="selectedAnswerForTimeSlots"
|
||||||
@update:modelValue="timeSlotSelectionChanged"
|
@update:modelValue="timeSlotSelectionChanged"
|
||||||
buttonTypeString="timeSlotModalListButton"
|
buttonTypeString="timeSlotModalListButton"
|
||||||
:buttonTypeObject="timeSlotModalListButton"
|
:buttonTypeObject="timeSlotModalListButton"
|
||||||
|
|
@ -34,10 +36,12 @@
|
||||||
isInshopOrDropOffAppointment ? 'is-inshop-or-drop-off-appointment' : '',
|
isInshopOrDropOffAppointment ? 'is-inshop-or-drop-off-appointment' : '',
|
||||||
]"
|
]"
|
||||||
:answers="availableTimeSlots"
|
:answers="availableTimeSlots"
|
||||||
:lazyLoad="{ isLazyLoad: !isMobileAppointment, amountToLoad: 10 }"
|
:lazyLoad="{
|
||||||
|
isLazyLoad: !isMobileAppointment && !selectedAnswerForTimeSlots,
|
||||||
|
amountToLoad: 10,
|
||||||
|
}"
|
||||||
groupName="chooseTimeSlot"
|
groupName="chooseTimeSlot"
|
||||||
textPosition="text-center"
|
textPosition="text-center"
|
||||||
v-model="selectedAnswerForTimeSlots"
|
|
||||||
questionText="Available times:"
|
questionText="Available times:"
|
||||||
isRequired
|
isRequired
|
||||||
validationRules="time-slot-required" />
|
validationRules="time-slot-required" />
|
||||||
|
|
@ -389,7 +393,7 @@ export default {
|
||||||
this.answersForDropOffQuestion[0].value !== PICK_A_TIME_BUTTON_VALUE
|
this.answersForDropOffQuestion[0].value !== PICK_A_TIME_BUTTON_VALUE
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
shouldDisplayTimeSlotQuestion() {
|
displayTimeSlotQuestion() {
|
||||||
return (
|
return (
|
||||||
this.selectedAnswerForDropOffOrInshop == PICK_A_TIME_BUTTON_VALUE ||
|
this.selectedAnswerForDropOffOrInshop == PICK_A_TIME_BUTTON_VALUE ||
|
||||||
!this.isDropOffAppointmentAvailable
|
!this.isDropOffAppointmentAvailable
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ export default {
|
||||||
},
|
},
|
||||||
set: function (newValue) {
|
set: function (newValue) {
|
||||||
this.$emit("update:modelValue", newValue);
|
this.$emit("update:modelValue", newValue);
|
||||||
|
this.$emit("handle-appointment-type-change", newValue);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isMobileOnly() {
|
isMobileOnly() {
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ const navigationScenarios = {
|
||||||
// Payment
|
// Payment
|
||||||
CLICKED_INSURANCE: "CLICKED_INSURANCE",
|
CLICKED_INSURANCE: "CLICKED_INSURANCE",
|
||||||
CLICKED_PAY_NOW: "CLICKED_PAY_NOW",
|
CLICKED_PAY_NOW: "CLICKED_PAY_NOW",
|
||||||
|
CLICKED_PAY_NOW_ADYEN: "CLICKED_PAY_NOW_ADYEN",
|
||||||
CLICKED_PAY_LATER: "CLICKED_PAY_LATER",
|
CLICKED_PAY_LATER: "CLICKED_PAY_LATER",
|
||||||
PIA_ERROR: "PIA_ERROR",
|
PIA_ERROR: "PIA_ERROR",
|
||||||
PIA_CC_ERROR: "PIA_CC_ERROR",
|
PIA_CC_ERROR: "PIA_CC_ERROR",
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,15 @@ export const routeData = {
|
||||||
name: "payment-pia-return",
|
name: "payment-pia-return",
|
||||||
path: "/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: {
|
CONFIRMATION: {
|
||||||
name: "confirmation",
|
name: "confirmation",
|
||||||
path: "/confirmation",
|
path: "/confirmation",
|
||||||
|
|
|
||||||
|
|
@ -537,6 +537,10 @@ const routingTable = function () {
|
||||||
scenario: navigationScenarios.CLICKED_PAY_NOW,
|
scenario: navigationScenarios.CLICKED_PAY_NOW,
|
||||||
destinationPageData: routeData.PAYMENT,
|
destinationPageData: routeData.PAYMENT,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_PAY_NOW_ADYEN,
|
||||||
|
destinationPageData: routeData.PAYMENT_ADYEN,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_INSURANCE,
|
scenario: navigationScenarios.CLICKED_INSURANCE,
|
||||||
destinationPageData: routeData.INSURANCE_COMPANY,
|
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,
|
pageName: routeData.PAYMENT_PIA_RETURN.name,
|
||||||
maps: [
|
maps: [
|
||||||
|
|
|
||||||
118
src/router/methods/route-logic/adyen-return.js
Normal file
118
src/router/methods/route-logic/adyen-return.js
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
import { routeData } from "@/router/constants/routes";
|
||||||
|
import { createAdyenCheckout, getSessionInfo } from "@/helpers/adyen-helper";
|
||||||
|
import { mapAdyenToFmgPaymentMethod, generateCcToken } from "@/helpers/adyen-helper";
|
||||||
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
import { getAmountDue } from "@/helpers/pricing-helper";
|
||||||
|
import store from "@/store";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
||||||
|
|
||||||
|
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.
|
||||||
|
const paymentMethod = mapAdyenToFmgPaymentMethod(sessionInfo?.paymentMethod);
|
||||||
|
const amountDue = getAmountDue(store.getters.order.lineItems);
|
||||||
|
const ccToken = generateCcToken(sessionInfo);
|
||||||
|
|
||||||
|
ccToken.authCode = "831001";
|
||||||
|
ccToken.cardType = "VS";
|
||||||
|
ccToken.lastFour = "1111";
|
||||||
|
ccToken.expMonth = "03";
|
||||||
|
ccToken.expYear = "2030";
|
||||||
|
|
||||||
|
await baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
||||||
|
paymentMethod,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
await baseMixin.methods.dispatchStoreAction(storeActions.SAVE_CCTOKEN, ccToken, false);
|
||||||
|
|
||||||
|
await baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||||
|
amountDue,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
await baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await submitWorkOrder({
|
||||||
|
pageNameToLog: "adyen-return",
|
||||||
|
submitAfterSave: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return {
|
||||||
|
name: routeData.ERROR.name,
|
||||||
|
replace: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_STATE);
|
||||||
|
|
||||||
|
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 { paymentMethodBeforeEnter } from "@/router/methods/route-logic/payment-method";
|
||||||
import { paymentBeforeEnter } from "@/router/methods/route-logic/payment";
|
import { paymentBeforeEnter } from "@/router/methods/route-logic/payment";
|
||||||
import { serviceLocationBeforeEnter } from "@/router/methods/route-logic/service-location";
|
import { serviceLocationBeforeEnter } from "@/router/methods/route-logic/service-location";
|
||||||
|
import { adyenReturnBeforeEnter } from "@/router/methods/route-logic/adyen-return";
|
||||||
|
|
||||||
export const routes = [
|
export const routes = [
|
||||||
// Non-virtual pages.
|
// Non-virtual pages.
|
||||||
|
|
@ -36,6 +37,7 @@ export const routes = [
|
||||||
createRoute(routeData.PAYMENT_METHOD, paymentMethodBeforeEnter),
|
createRoute(routeData.PAYMENT_METHOD, paymentMethodBeforeEnter),
|
||||||
createRoute(routeData.PAYMENT, paymentBeforeEnter),
|
createRoute(routeData.PAYMENT, paymentBeforeEnter),
|
||||||
createRoute(routeData.PAYMENT_PIA_RETURN),
|
createRoute(routeData.PAYMENT_PIA_RETURN),
|
||||||
|
createRoute(routeData.PAYMENT_ADYEN),
|
||||||
createRoute(routeData.CONFIRMATION),
|
createRoute(routeData.CONFIRMATION),
|
||||||
createRoute(routeData.RETURN_USER),
|
createRoute(routeData.RETURN_USER),
|
||||||
createRoute(routeData.MOBILE_DETAILS),
|
createRoute(routeData.MOBILE_DETAILS),
|
||||||
|
|
@ -47,4 +49,5 @@ export const routes = [
|
||||||
createVirtualRoute(routeData.AUTO_ROUTE, autoRouteBeforeEnter),
|
createVirtualRoute(routeData.AUTO_ROUTE, autoRouteBeforeEnter),
|
||||||
createVirtualRoute(routeData.ERROR, errorBeforeEnter),
|
createVirtualRoute(routeData.ERROR, errorBeforeEnter),
|
||||||
createVirtualRoute(routeData.RESTART, restartBeforeEnter),
|
createVirtualRoute(routeData.RESTART, restartBeforeEnter),
|
||||||
|
createVirtualRoute(routeData.PAYMENT_ADYEN_RETURN, adyenReturnBeforeEnter),
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1765,7 +1765,8 @@ export const actions = {
|
||||||
const glassArray = damage.glassToReplace;
|
const glassArray = damage.glassToReplace;
|
||||||
const zipCode = order.serviceLocation.zipCode;
|
const zipCode = order.serviceLocation.zipCode;
|
||||||
const vin = vehicle.vin;
|
const vin = vehicle.vin;
|
||||||
const serviceType = order.serviceLocation?.appointmentType;
|
const serviceType = damage.isRepair ? "Repair" : "Install";
|
||||||
|
const parentAccountNumber = context.getters.payment.parentAccountNumber;
|
||||||
const referralSeqNumber = order.referralSequenceNumber;
|
const referralSeqNumber = order.referralSequenceNumber;
|
||||||
|
|
||||||
// create a new array to avoid mutating state
|
// create a new array to avoid mutating state
|
||||||
|
|
@ -1781,6 +1782,7 @@ export const actions = {
|
||||||
vin: vin,
|
vin: vin,
|
||||||
serviceType: serviceType,
|
serviceType: serviceType,
|
||||||
referralSeqNumber: referralSeqNumber,
|
referralSeqNumber: referralSeqNumber,
|
||||||
|
parentAccountNumber: parentAccountNumber,
|
||||||
},
|
},
|
||||||
logApiCall: true,
|
logApiCall: true,
|
||||||
pageNameToLog: pageNameToLog,
|
pageNameToLog: pageNameToLog,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue