diff --git a/enabler/dev-utils/session.js b/enabler/dev-utils/session.js
index 119978f..0d7f0dd 100644
--- a/enabler/dev-utils/session.js
+++ b/enabler/dev-utils/session.js
@@ -58,7 +58,8 @@ const getSessionId = async (cartId, isDropin = false) => {
"bancontactmobile",
"twint",
"sepadirectdebit",
- "klarna_billie"
+ "klarna_billie",
+ "amazonpay"
], // add here your allowed methods for development purposes
}),
};
diff --git a/enabler/src/components/base.ts b/enabler/src/components/base.ts
index ae7c59a..6818f72 100644
--- a/enabler/src/components/base.ts
+++ b/enabler/src/components/base.ts
@@ -8,7 +8,8 @@ import {
Klarna,
EPS,
Twint,
- SepaDirectDebit
+ SepaDirectDebit,
+ AmazonPay
} from "@adyen/adyen-web";
import {
ComponentOptions,
@@ -27,7 +28,8 @@ type AdyenComponent =
| EPS
| Twint
| Redirect
- | SepaDirectDebit;
+ | SepaDirectDebit
+ | AmazonPay;
/**
* Base Web Component
diff --git a/enabler/src/components/payment-methods/amazonpay.ts b/enabler/src/components/payment-methods/amazonpay.ts
new file mode 100644
index 0000000..3a166ec
--- /dev/null
+++ b/enabler/src/components/payment-methods/amazonpay.ts
@@ -0,0 +1,69 @@
+import {
+ ComponentOptions,
+ PaymentMethod,
+} from "../../payment-enabler/payment-enabler";
+import { AdyenBaseComponentBuilder, DefaultAdyenComponent } from "../base";
+import { BaseOptions } from "../../payment-enabler/adyen-payment-enabler";
+import { AmazonPay, ICore } from "@adyen/adyen-web";
+
+/**
+ * Amazon pay component
+ *
+ * Configuration options:
+ * https://docs.adyen.com/payment-methods/amazon-pay/web-component/
+ */
+export class AmazonpayBuilder extends AdyenBaseComponentBuilder {
+ public componentHasSubmit = false;
+
+ constructor(baseOptions: BaseOptions) {
+ super(PaymentMethod.amazonpay, baseOptions);
+ }
+
+ build(config: ComponentOptions): AmazonPayComponent {
+ const amazonPayComponent = new AmazonPayComponent({
+ paymentMethod: this.paymentMethod,
+ adyenCheckout: this.adyenCheckout,
+ componentOptions: config,
+ sessionId: this.sessionId,
+ processorUrl: this.processorUrl,
+ });
+ amazonPayComponent.init();
+
+ return amazonPayComponent;
+ }
+}
+
+export class AmazonPayComponent extends DefaultAdyenComponent {
+ constructor(opts: {
+ paymentMethod: PaymentMethod;
+ adyenCheckout: ICore;
+ componentOptions: ComponentOptions;
+ sessionId: string;
+ processorUrl: string;
+ usesOwnCertificate?: boolean;
+ }) {
+ super(opts);
+ }
+
+ init(): void {
+ const returnUrl = this.processorUrl.endsWith("/")
+ ? `${this.processorUrl}payments/amazonpay?step=review&sessionId=${this.sessionId}`
+ : `${this.processorUrl}/payments/amazonpay?step=review&sessionId=${this.sessionId}`;
+
+ this.component = new AmazonPay(this.adyenCheckout, {
+ showPayButton: this.componentOptions.showPayButton,
+ productType: 'PayOnly',
+ // environment: 'test', // we can add an additional environment variable for the enabler for this, or add it to the baseOptions to be passed by the user of the enabler
+ returnUrl,
+ onClick: (resolve, reject) => {
+ if (this.componentOptions.onPayButtonClick) {
+ return this.componentOptions
+ .onPayButtonClick()
+ .then(() => resolve())
+ .catch((error) => reject(error));
+ }
+ return resolve();
+ },
+ });
+ }
+}
diff --git a/enabler/src/payment-enabler/adyen-payment-enabler.ts b/enabler/src/payment-enabler/adyen-payment-enabler.ts
index db280ca..d3380c1 100644
--- a/enabler/src/payment-enabler/adyen-payment-enabler.ts
+++ b/enabler/src/payment-enabler/adyen-payment-enabler.ts
@@ -33,6 +33,7 @@ import { DropinEmbeddedBuilder } from "../dropin/dropin-embedded";
import { SepaBuilder } from "../components/payment-methods/sepadirectdebit";
import { BancontactMobileBuilder } from "../components/payment-methods/bancontactcard-mobile";
import { KlarnaBillieBuilder } from "../components/payment-methods/klarna-billie";
+import { AmazonpayBuilder } from "../components/payment-methods/amazonpay";
class AdyenInitError extends Error {
sessionId: string;
@@ -231,6 +232,7 @@ export class AdyenPaymentEnabler implements PaymentEnabler {
twint: TwintBuilder,
sepadirectdebit: SepaBuilder,
klarna_billie: KlarnaBillieBuilder,
+ amazonpay: AmazonpayBuilder,
};
if (!Object.keys(supportedMethods).includes(type)) {
throw new Error(
diff --git a/enabler/src/payment-enabler/payment-enabler.ts b/enabler/src/payment-enabler/payment-enabler.ts
index 433790d..dc63140 100644
--- a/enabler/src/payment-enabler/payment-enabler.ts
+++ b/enabler/src/payment-enabler/payment-enabler.ts
@@ -43,7 +43,8 @@ export enum PaymentMethod {
bancontactmobile = "bcmc_mobile", // Bancontact mobile
twint = "twint",
sepadirectdebit = "sepadirectdebit",
- klarna_billie = "klarna_b2b" // Billie
+ klarna_billie = "klarna_b2b", // Billie
+ amazonpay = "amazonpay"
}
export type PaymentResult =
diff --git a/processor/package.json b/processor/package.json
index df5ff70..cebe996 100644
--- a/processor/package.json
+++ b/processor/package.json
@@ -10,7 +10,7 @@
"lint:fix": "prettier --write \"**/**/*.{ts,js,json}\" && eslint --fix --ext .ts src",
"build": "rm -rf /dist && tsc",
"dev": "ts-node src/main.ts",
- "watch": "nodemon --watch \"src/**\" --ext \"ts,json\" --ignore \"src/**/*.spec.ts\" --exec \"ts-node src/main.ts\"",
+ "watch": "nodemon --watch \"src/**\" --ext \"ts,json,html\" --ignore \"src/**/*.spec.ts\" --exec \"ts-node src/main.ts\"",
"test": "jest --detectOpenHandles",
"test:watch": "jest --watch --detectOpenHandles",
"test:coverage": "jest --detectOpenHandles --coverage",
diff --git a/processor/src/public/checkout.html b/processor/src/public/checkout.html
new file mode 100644
index 0000000..7d7e0be
--- /dev/null
+++ b/processor/src/public/checkout.html
@@ -0,0 +1,184 @@
+
+
+
+
+
+ Amazon Pay Checkout
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/processor/src/routes/adyen-payment.route.ts b/processor/src/routes/adyen-payment.route.ts
index 64dd68d..e858156 100644
--- a/processor/src/routes/adyen-payment.route.ts
+++ b/processor/src/routes/adyen-payment.route.ts
@@ -19,6 +19,11 @@ import {
} from '../dtos/adyen-payment.dto';
import { AdyenPaymentService } from '../services/adyen-payment.service';
import { HmacAuthHook } from '../libs/fastify/hooks/hmac-auth.hook';
+import path from 'node:path';
+import fastifyStatic from '@fastify/static';
+import { getConfig } from '../config/config';
+import { promisify } from 'node:util';
+import { readFile } from 'fs';
type PaymentRoutesOptions = {
paymentService: AdyenPaymentService;
@@ -31,6 +36,14 @@ export const adyenPaymentRoutes = async (
fastify: FastifyInstance,
opts: FastifyPluginOptions & PaymentRoutesOptions,
) => {
+ // Serve static files (HTML, CSS, JS)
+ fastify.register(fastifyStatic, {
+ root: path.join(__dirname, 'public'),
+ prefix: '/public/',
+ });
+
+ const readFileAsync = promisify(readFile);
+
fastify.post<{ Body: PaymentMethodsRequestDTO; Reply: PaymentMethodsResponseDTO }>(
'/payment-methods',
{
@@ -90,6 +103,39 @@ export const adyenPaymentRoutes = async (
},
);
+ fastify.get<{
+ Reply: string;
+ Querystring: {
+ paymentReference: string;
+ redirectResult?: string;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ [key: string]: any;
+ };
+ }>(
+ '/payments/amazonpay',
+ {
+ preHandler: [],
+ },
+ async (request, reply) => {
+ //HINT: add check here for amazon session ID and return a html here
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const queryParams = request.query as any;
+
+ if (queryParams.amazonCheckoutSessionId) {
+ const filePath = path.join(__dirname, '../public/checkout.html');
+ const fileContent = await readFileAsync(filePath, 'utf8');
+
+ // Inject the environment variable into the HTML content
+ const htmlWithEnv = fileContent
+ .replace('{{ADYEN_CLIENT_KEY}}', getConfig().adyenClientKey)
+ .replace('{{ENVIRONMENT}}', getConfig().adyenEnvironment);
+ return reply.type('text/html').send(htmlWithEnv);
+ }
+
+ return reply.send('missing query parameters');
+ },
+ );
+
fastify.get<{
Reply: ConfirmPaymentResponseDTO;
Querystring: {
@@ -104,8 +150,10 @@ export const adyenPaymentRoutes = async (
preHandler: [opts.sessionQueryParamAuthHook.authenticate()],
},
async (request, reply) => {
+ //HINT: add check here for amazon session ID and return a html here
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const queryParams = request.query as any;
+
const res = await opts.paymentService.confirmPayment({
data: {
details: {
diff --git a/processor/src/services/converters/capture-payment.converter.ts b/processor/src/services/converters/capture-payment.converter.ts
index ac3a835..ca03973 100644
--- a/processor/src/services/converters/capture-payment.converter.ts
+++ b/processor/src/services/converters/capture-payment.converter.ts
@@ -13,7 +13,7 @@ import {
/**
* These payment methods require line items to be send to Adyen for capturing payments
*/
-export const METHODS_REQUIRE_LINE_ITEMS = ['klarna', 'klarna_account', 'klarna_paynow', 'klarna_b2b'];
+export const METHODS_REQUIRE_LINE_ITEMS = ['klarna', 'klarna_account', 'klarna_paynow', 'klarna_b2b', 'amazonpay'];
export class CapturePaymentConverter {
private ctCartService: CommercetoolsCartService;
diff --git a/processor/src/services/converters/create-payment.converter.ts b/processor/src/services/converters/create-payment.converter.ts
index 3f7e93f..d866608 100644
--- a/processor/src/services/converters/create-payment.converter.ts
+++ b/processor/src/services/converters/create-payment.converter.ts
@@ -37,6 +37,7 @@ export class CreatePaymentConverter {
case 'klarna':
case 'klarna_paynow':
case 'klarna_b2b':
+ case 'amazonpay':
case 'klarna_account': {
return {
lineItems: mapCoCoCartItemsToAdyenLineItems(cart),
diff --git a/processor/src/services/converters/payment-components.converter.ts b/processor/src/services/converters/payment-components.converter.ts
index 2290f28..7d71c31 100644
--- a/processor/src/services/converters/payment-components.converter.ts
+++ b/processor/src/services/converters/payment-components.converter.ts
@@ -51,6 +51,9 @@ export class PaymentComponentsConverter {
{
type: 'klarna_billie', // klarna_b2b
},
+ {
+ type: 'amazonpay',
+ },
],
};
}
diff --git a/processor/test/services/adyen-payment.service.spec.ts b/processor/test/services/adyen-payment.service.spec.ts
index df016a9..a81f654 100644
--- a/processor/test/services/adyen-payment.service.spec.ts
+++ b/processor/test/services/adyen-payment.service.spec.ts
@@ -98,7 +98,7 @@ describe('adyen-payment.service', () => {
test('getSupportedPaymentComponents', async () => {
const result: SupportedPaymentComponentsSchemaDTO = await paymentService.getSupportedPaymentComponents();
- expect(result?.components).toHaveLength(14);
+ expect(result?.components).toHaveLength(15);
expect(result?.components[0]?.type).toStrictEqual('card');
expect(result?.components[1]?.type).toStrictEqual('ideal');
expect(result?.components[2]?.type).toStrictEqual('paypal');
@@ -113,6 +113,7 @@ describe('adyen-payment.service', () => {
expect(result?.components[11]?.type).toStrictEqual('twint');
expect(result?.components[12]?.type).toStrictEqual('sepadirectdebit');
expect(result?.components[13]?.type).toStrictEqual('klarna_billie');
+ expect(result?.components[14]?.type).toStrictEqual('amazonpay');
});
test('getStatus', async () => {
diff --git a/processor/test/services/converters/capture.converter.spec.ts b/processor/test/services/converters/capture.converter.spec.ts
index 69835b7..6cb8821 100644
--- a/processor/test/services/converters/capture.converter.spec.ts
+++ b/processor/test/services/converters/capture.converter.spec.ts
@@ -3,7 +3,7 @@ import { METHODS_REQUIRE_LINE_ITEMS } from '../../../src/services/converters/cap
describe('capture.converter', () => {
test('METHODS_REQUIRE_LINE_ITEMS', () => {
- const expected = ['klarna', 'klarna_account', 'klarna_paynow', 'klarna_b2b'];
+ const expected = ['klarna', 'klarna_account', 'klarna_paynow', 'klarna_b2b', 'amazonpay'];
expect(METHODS_REQUIRE_LINE_ITEMS).toEqual(expected);
});
});