From 43cfca81899f4788010f556ac3249b44e0c8f249 Mon Sep 17 00:00:00 2001 From: shij Date: Wed, 6 Nov 2024 18:19:41 +0800 Subject: [PATCH] feat(payment): support create pending payment --- .../steps/create-payment-session.ts | 2 +- .../workflows/create-payment-session.ts | 2 +- packages/core/types/src/payment/mutations.ts | 7 +- ...02113510.ts => Migration20241106090002.ts} | 5 +- .../payment/src/models/payment-session.ts | 4 +- .../payment/src/services/payment-module.ts | 165 ++++++++++++------ 6 files changed, 128 insertions(+), 57 deletions(-) rename packages/modules/payment/src/migrations/{Migration20240902113510.ts => Migration20241106090002.ts} (78%) diff --git a/packages/core/core-flows/src/payment-collection/steps/create-payment-session.ts b/packages/core/core-flows/src/payment-collection/steps/create-payment-session.ts index 4a5e6f12adaa5..3c90db65a05d9 100644 --- a/packages/core/core-flows/src/payment-collection/steps/create-payment-session.ts +++ b/packages/core/core-flows/src/payment-collection/steps/create-payment-session.ts @@ -8,7 +8,7 @@ import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk" export interface CreatePaymentSessionStepInput { payment_collection_id: string - provider_id: string + provider_id?: string provider_token?: string amount?: BigNumberInput context?: PaymentProviderContext diff --git a/packages/core/core-flows/src/payment-collection/workflows/create-payment-session.ts b/packages/core/core-flows/src/payment-collection/workflows/create-payment-session.ts index 3c63bde5dd09a..101afdf794c11 100644 --- a/packages/core/core-flows/src/payment-collection/workflows/create-payment-session.ts +++ b/packages/core/core-flows/src/payment-collection/workflows/create-payment-session.ts @@ -12,7 +12,7 @@ import { createPaymentSessionStep } from "../steps" export interface CreatePaymentSessionsWorkflowInput { payment_collection_id: string - provider_id: string + provider_id?: string provider_token?: string amount?: BigNumberInput context?: PaymentProviderContext diff --git a/packages/core/types/src/payment/mutations.ts b/packages/core/types/src/payment/mutations.ts index 642aef7579f10..6e20a7a76dcad 100644 --- a/packages/core/types/src/payment/mutations.ts +++ b/packages/core/types/src/payment/mutations.ts @@ -226,7 +226,7 @@ export interface CreatePaymentSessionDTO { /** * The provider's ID. */ - provider_id: string + provider_id?: string /** * The provider's payment method token @@ -258,6 +258,11 @@ export interface UpdatePaymentSessionDTO { */ id: string + /** + * The provider's ID. + */ + provider_id?: string + /** * The provider's payment method token */ diff --git a/packages/modules/payment/src/migrations/Migration20240902113510.ts b/packages/modules/payment/src/migrations/Migration20241106090002.ts similarity index 78% rename from packages/modules/payment/src/migrations/Migration20240902113510.ts rename to packages/modules/payment/src/migrations/Migration20241106090002.ts index 3509c56b49f61..cae1daf311b5d 100644 --- a/packages/modules/payment/src/migrations/Migration20240902113510.ts +++ b/packages/modules/payment/src/migrations/Migration20241106090002.ts @@ -1,6 +1,6 @@ import { Migration } from "@mikro-orm/migrations" -export class Migration20240902113510 extends Migration { +export class Migration20241106090002 extends Migration { async up(): Promise { this.addSql( 'alter table if exists "capture" add column if not exists "data" jsonb not null;' @@ -14,6 +14,9 @@ export class Migration20240902113510 extends Migration { this.addSql( 'alter table if exists "payment_session" drop constraint if exists "payment_session_status_check";' ) + this.addSql( + 'alter table if exists "payment_session" alter column "provider_id" drop not null;' + ) } async down(): Promise { diff --git a/packages/modules/payment/src/models/payment-session.ts b/packages/modules/payment/src/models/payment-session.ts index 6375d812155ca..0da6d3d5a60ba 100644 --- a/packages/modules/payment/src/models/payment-session.ts +++ b/packages/modules/payment/src/models/payment-session.ts @@ -38,8 +38,8 @@ export default class PaymentSession { }) raw_amount: BigNumberRawValue - @Property({ columnType: "text" }) - provider_id: string + @Property({ columnType: "text", nullable: true }) + provider_id: string | null = null @Property({ columnType: "jsonb" }) data: Record = {} diff --git a/packages/modules/payment/src/services/payment-module.ts b/packages/modules/payment/src/services/payment-module.ts index f0e98b3d8a4d0..8e77b7a5e3c66 100644 --- a/packages/modules/payment/src/services/payment-module.ts +++ b/packages/modules/payment/src/services/payment-module.ts @@ -345,24 +345,32 @@ export default class PaymentModuleService sharedContext ) - try { - res = await this.paymentProviderService_.createSession(data.provider_id, { - amount, - currency_code: paymentCollection.currency_code, - context: { ...data.context, session_id: paymentSession.id }, - token: data.provider_token, - }) - } catch (err) { - await this.paymentSessionService_.delete(paymentSession.id, sharedContext) - throw err - } + if (data.provider_id) { + try { + res = await this.paymentProviderService_.createSession( + data.provider_id, + { + amount, + currency_code: paymentCollection.currency_code, + context: { ...data.context, session_id: paymentSession.id }, + token: data.provider_token, + } + ) + } catch (err) { + await this.paymentSessionService_.delete( + paymentSession.id, + sharedContext + ) + throw err + } - await this.handleProviderSessionResponse_(res, sharedContext) - paymentSession = await this.paymentSessionService_.retrieve( - paymentSession.id, - {}, - sharedContext - ) + await this.handleProviderSessionResponse_(res, sharedContext) + paymentSession = await this.paymentSessionService_.retrieve( + paymentSession.id, + {}, + sharedContext + ) + } return this.baseRepository_.serialize(paymentSession, { populate: true }) } @@ -372,35 +380,79 @@ export default class PaymentModuleService data: UpdatePaymentSessionDTO, @MedusaContext() sharedContext?: Context ): Promise { + const session = await this.paymentSessionService_.retrieve(data.id, { + select: [ + "id", + "data", + "context", + "provider_id", + "metadata", + "currency_code", + "raw_amount", + ], + }) + let res: PaymentProviderSessionResponse | undefined + if ( - !data.amount && - !data.context && - !data.provider_token && - !data.metadata + data.provider_id && + session.provider_id && + data.provider_id !== session.provider_id ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `The payment session update requires at least an amount, context, provider token or metadata.` + res = await this.paymentProviderService_.cancelPayment( + session.provider_id, + session.data ) } - const session = await this.paymentSessionService_.retrieve(data.id, { - select: ["id", "data", "context", "provider_id", "metadata"], - }) + if ( + data.provider_id && + (!session.provider_id || data.provider_id !== session.provider_id) + ) { + try { + res = await this.paymentProviderService_.createSession( + data.provider_id, + { + amount: data.amount ?? session.raw_amount, + currency_code: session.currency_code, + context: { + ...session.context, + ...data.context, + session_id: session.id, + }, + token: data.provider_token, + } + ) + } catch (err) { + if (res) { + await this.handleProviderSessionResponse_(res, sharedContext) + } + throw err + } + } else if (session.provider_id) { + res = await this.paymentProviderService_.updateSession( + session.provider_id, + { + data: session.data, + context: { + ...session.context, + ...data.context, + session_id: session.id, + }, + amount: data.amount, + token: data.provider_token, + } + ) + } - await this.handleProviderSessionResponse_( - await this.paymentProviderService_.updateSession(session.provider_id, { - data: session.data, - context: { - ...session.context, - ...data.context, - session_id: session.id, - }, - amount: data.amount, - token: data.provider_token, - }), - sharedContext - ) + if (res) { + if (data.provider_id && data.provider_id !== session.provider_id) { + await this.paymentSessionService_.update( + { id: session.id, provider_id: data.provider_id }, + sharedContext + ) + } + await this.handleProviderSessionResponse_(res, sharedContext) + } if (data.amount || data.context || data.metadata) { const toUpdate: any = {} @@ -430,10 +482,12 @@ export default class PaymentModuleService sharedContext ) - await this.paymentProviderService_.deleteSession( - session.provider_id, - session.data - ) + if (session.provider_id) { + await this.paymentProviderService_.deleteSession( + session.provider_id, + session.data + ) + } await this.paymentSessionService_.delete(id, sharedContext) } @@ -450,6 +504,13 @@ export default class PaymentModuleService sharedContext ) + if (!paymentSession.provider_id) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `The payment session has not yet specified a provider.` + ) + } + await this.handleProviderSessionResponse_( await this.paymentProviderService_.authorizePayment( paymentSession.provider_id, @@ -549,13 +610,15 @@ export default class PaymentModuleService sharedContext ) - await this.handleProviderSessionResponse_( - await this.paymentProviderService_.cancelPayment( - paymentSession.provider_id, - paymentSession.data - ), - sharedContext - ) + if (paymentSession.provider_id) { + await this.handleProviderSessionResponse_( + await this.paymentProviderService_.cancelPayment( + paymentSession.provider_id, + paymentSession.data + ), + sharedContext + ) + } return this.retrievePaymentSession(id, {}, sharedContext) }