diff --git a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/bigcommerce-payments-alternative-methods-payment-strategy.ts b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/bigcommerce-payments-alternative-methods-payment-strategy.ts index 3c99b76c60..ae5e114344 100644 --- a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/bigcommerce-payments-alternative-methods-payment-strategy.ts +++ b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/bigcommerce-payments-alternative-methods-payment-strategy.ts @@ -37,6 +37,27 @@ import BigCommercePaymentsAlternativeMethodsPaymentInitializeOptions, { const POLLING_INTERVAL = 3000; const MAX_POLLING_TIME = 300000; +export interface RedirectActionBody { + body: { + additional_action_required: { + type: 'offsite_redirect'; + data: { + redirect_url: string; + }; + }; + }; +} + +export interface RedirectError { + body: { + additional_action_required: { + data: { + redirect_url: string; + }; + }; + }; +} + export default class BigCommercePaymentsAlternativeMethodsPaymentStrategy implements PaymentStrategy { @@ -56,7 +77,9 @@ export default class BigCommercePaymentsAlternativeMethodsPaymentStrategy private loadingIndicator: LoadingIndicator, private pollingInterval: number = POLLING_INTERVAL, private maxPollingIntervalTime: number = MAX_POLLING_TIME, - ) {} + ) { + console.log('BigCommercePaymentsAlternativeMethodsPaymentStrategy constructor test'); + } async initialize( options: PaymentInitializeOptions & @@ -64,6 +87,10 @@ export default class BigCommercePaymentsAlternativeMethodsPaymentStrategy ): Promise { const { gatewayId, methodId, bigcommerce_payments_apms } = options; + if (methodId === 'klarna') { + return; + } + this.bigCommercePaymentsAlternativeMethods = bigcommerce_payments_apms; if (!methodId) { @@ -128,25 +155,72 @@ export default class BigCommercePaymentsAlternativeMethodsPaymentStrategy const { methodId, gatewayId } = payment; - if (!this.orderId) { - throw new PaymentMethodInvalidError(); - } + if (methodId === 'klarna') { + try { + const orderId = await this.bigCommercePaymentsIntegrationService.createOrder( + 'bigcommerce_payments_apms', + { + gatewayId: 'bigcommerce_payments_apms', + methodId: 'klarna', + }, + ); - if (this.isPollingEnabled && methodId === 'ideal') { - await new Promise((resolve, reject) => { - void this.initializePollingMechanism(methodId, resolve, reject, gatewayId); - }); - } + const paymentData = { + formattedPayload: { + vault_payment_instrument: null, + set_as_default_stored_instrument: null, + device_info: null, + method_id: methodId, + paypal_account: { + order_id: orderId, + }, + }, + }; + + await this.paymentIntegrationService.submitOrder(order, options); + await this.paymentIntegrationService.submitPayment({ + methodId, + gatewayId, + paymentData, + }); + } catch (error: unknown) { + if (this.isRedirectError(error)) { + const redirectUrl = error.body.additional_action_required.data.redirect_url; - if (!this.isNonInstantPaymentMethod(methodId)) { - await this.paymentIntegrationService.submitOrder(order, options); - } + return new Promise((_, reject) => { + window.location.replace(redirectUrl); - await this.bigCommercePaymentsIntegrationService.submitPayment( - methodId, - this.orderId, - gatewayId, - ); + this.toggleLoadingIndicator(false); + + reject(); + }); + } + + this.handleError(error); + + return Promise.reject(error); + } + } else { + if (!this.orderId) { + throw new PaymentMethodInvalidError(); + } + + if (this.isPollingEnabled && methodId === 'ideal') { + await new Promise((resolve, reject) => { + void this.initializePollingMechanism(methodId, resolve, reject, gatewayId); + }); + } + + if (!this.isNonInstantPaymentMethod(methodId)) { + await this.paymentIntegrationService.submitOrder(order, options); + } + + await this.bigCommercePaymentsIntegrationService.submitPayment( + methodId, + this.orderId, + gatewayId, + ); + } } finalize(): Promise { @@ -445,4 +519,18 @@ export default class BigCommercePaymentsAlternativeMethodsPaymentStrategy return this.paypalApms; } + + private isRedirectError(error: unknown): error is RedirectError { + if (typeof error !== 'object' || error === null) { + return false; + } + + const { body }: Partial = error; + + if (!body) { + return false; + } + + return !!body.additional_action_required?.data.redirect_url; + } } diff --git a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/create-bigcommerce-payments-alternative-methods-button-strategy.ts b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/create-bigcommerce-payments-alternative-methods-button-strategy.ts index 78e40a4859..1507d1d672 100644 --- a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/create-bigcommerce-payments-alternative-methods-button-strategy.ts +++ b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/create-bigcommerce-payments-alternative-methods-button-strategy.ts @@ -16,5 +16,5 @@ const createBigCommercePaymentsAlternativeMethodsButtonStrategy: CheckoutButtonS ); export default toResolvableModule(createBigCommercePaymentsAlternativeMethodsButtonStrategy, [ - { id: 'bigcommerce_payments_apms' }, + { gateway: 'bigcommerce_payments_apms' }, ]); diff --git a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/create-bigcommerce-payments-alternative-methods-payment-strategy.ts b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/create-bigcommerce-payments-alternative-methods-payment-strategy.ts index b828cba74b..0fcb2a7a78 100644 --- a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/create-bigcommerce-payments-alternative-methods-payment-strategy.ts +++ b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-alternative-methods/create-bigcommerce-payments-alternative-methods-payment-strategy.ts @@ -12,8 +12,10 @@ import BigCommercePaymentsAlternativeMethodsPaymentStrategy from './bigcommerce- const createBigCommercePaymentsAlternativeMethodsPaymentStrategy: PaymentStrategyFactory< BigCommercePaymentsAlternativeMethodsPaymentStrategy -> = (paymentIntegrationService) => - new BigCommercePaymentsAlternativeMethodsPaymentStrategy( +> = (paymentIntegrationService) => { + console.log('createBigCommercePaymentsAlternativeMethodsPaymentStrategy'); + + return new BigCommercePaymentsAlternativeMethodsPaymentStrategy( paymentIntegrationService, createBigCommercePaymentsIntegrationService(paymentIntegrationService), createBigCommercePaymentsSdk(), @@ -21,7 +23,10 @@ const createBigCommercePaymentsAlternativeMethodsPaymentStrategy: PaymentStrateg containerStyles: LOADING_INDICATOR_STYLES, }), ); +} + export default toResolvableModule(createBigCommercePaymentsAlternativeMethodsPaymentStrategy, [ - { gateway: 'bigcommerce_payments_apms' }, + // { gateway: 'bigcommerce_payments_apms' }, + { gateway: 'bigcommerce_payments_apms', id: 'klarna' }, ]); diff --git a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-types.ts b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-types.ts index 3e2d47bedc..ffae6fe4de 100644 --- a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-types.ts +++ b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-types.ts @@ -606,6 +606,8 @@ export interface PayPalCreateOrderRequestBody extends HostedInstrument, VaultedI metadataId?: string; setupToken?: boolean; fastlaneToken?: string; + methodId?: string; + gatewayId?: string; } export enum PayPalOrderStatus { diff --git a/packages/payment-integration-api/src/to-resolvable-module.ts b/packages/payment-integration-api/src/to-resolvable-module.ts index ff44d90278..70676eff4e 100644 --- a/packages/payment-integration-api/src/to-resolvable-module.ts +++ b/packages/payment-integration-api/src/to-resolvable-module.ts @@ -4,5 +4,7 @@ export default function toResolvableModule( module: TModule, resolveIds: TIdentifier[], ): ResolvableModule { + console.log('resolveIds', resolveIds); + return Object.assign(module, { resolveIds }); }