Skip to content

Commit

Permalink
feat: support payment session cancellation
Browse files Browse the repository at this point in the history
  • Loading branch information
silenaker committed Sep 26, 2024
1 parent cb27a57 commit a7563ab
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 34 deletions.
15 changes: 15 additions & 0 deletions packages/core/types/src/payment/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,21 @@ export interface IPaymentModuleService extends IModuleService {
sharedContext?: Context
): Promise<PaymentDTO>

/**
* This method cancels a payment session.
*
* @param {string} id - The ID of the payment session.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<PaymentSessionDTO>} The payment session's details.
*
* @example
* const paymentSession = await paymentModuleService.cancelPaymentSession("payses_123")
*/
cancelPaymentSession(
id: string,
sharedContext?: Context
): Promise<PaymentSessionDTO>

/**
* This method retrieves a paginated list of payment sessions based on optional filters and configuration.
*
Expand Down
108 changes: 74 additions & 34 deletions packages/modules/payment/src/services/payment-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,77 @@ export default class PaymentModuleService
)
}

@InjectManager("baseRepository_")
async cancelPaymentSession(
id: string,
@MedusaContext() sharedContext?: Context
): Promise<PaymentSessionDTO> {
const paymentSession = await this.paymentSessionService_.retrieve(
id,
{ select: ["data", "provider_id"] },
sharedContext
)

await this.handleProviderSessionResponse_(
await this.paymentProviderService_.cancelPayment(
paymentSession.provider_id,
paymentSession.data
),
sharedContext
)

return this.retrievePaymentSession(paymentSession.id, {}, sharedContext)
}

@InjectManager("baseRepository_")
private async cancelPaymentSession_(
id: string,
data?: PaymentProviderSessionResponse["data"],
@MedusaContext() sharedContext?: Context
): Promise<PaymentSession> {
let session = await this.paymentSessionService_.retrieve(
id,
{ select: ["status"], relations: ["payment"] },
sharedContext
)

if (session.status === PaymentSessionStatus.CANCELED) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`The payment session: ${session.id} has been canceled.`
)
}

if (
session.status !== PaymentSessionStatus.PENDING &&
session.status !== PaymentSessionStatus.REQUIRES_MORE &&
session.status !== PaymentSessionStatus.AUTHORIZED
) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`The payment session: ${session.id} cannot be canceled.`
)
}

if (session.payment) {
await this.paymentService_.update(
{
id: session.payment.id,
canceled_at: new Date(),
data,
},
sharedContext
)
}

session = await this.paymentSessionService_.update(
{ id, data, status: PaymentSessionStatus.CANCELED },
sharedContext
)

return session
}

@InjectManager("baseRepository_")
// @ts-expect-error
async retrievePaymentSession(
Expand Down Expand Up @@ -1075,43 +1146,12 @@ export default class PaymentModuleService
break
}
case "canceled": {
await this.paymentSessionService_.update(
{ id: session_id, data, status },
sharedContext
)
const session = await this.paymentSessionService_.retrieve(
const session = await this.cancelPaymentSession_(
session_id,
{
select: ["payment_collection_id"],
relations: ["payment", "payment.captures"],
},
data,
sharedContext
)
if (session.payment) {
if (session.payment.captures.length > 0) {
await this.paymentService_.update(
{
id: session.payment.id,
captured_at: new Date(),
data,
},
sharedContext
)
} else {
await this.paymentService_.update(
{
id: session.payment.id,
canceled_at: new Date(),
data,
},
sharedContext
)
}

await this.maybeUpdatePaymentCollection_(
session.payment_collection_id
)
}
await this.maybeUpdatePaymentCollection_(session.payment_collection_id)
break
}
default: {
Expand Down

0 comments on commit a7563ab

Please sign in to comment.