Skip to content

Commit

Permalink
feat: add payment authorization workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
silenaker committed Oct 15, 2024
1 parent e9dc185 commit 8b65f89
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 114 deletions.
5 changes: 3 additions & 2 deletions packages/core/core-flows/src/cart/workflows/complete-cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
useRemoteQueryStep,
} from "../../common"
import { createOrdersStep } from "../../order/steps/create-orders"
import { authorizePaymentSessionStep } from "../../payment/steps/authorize-payment-session"
import { authorizePaymentSessionStep } from "../../payment-collection"
import { registerUsageStep } from "../../promotion/steps/register-usage"
import { updateCartsStep, validateCartPaymentsStep } from "../steps"
import { reserveInventoryStep } from "../steps/reserve-inventory"
Expand All @@ -36,6 +36,7 @@ import {

export type CompleteCartWorkflowInput = {
id: string
provider_token?: string
}

export const completeCartWorkflowId = "complete-cart"
Expand All @@ -62,7 +63,7 @@ export const completeCartWorkflow = createWorkflow(
// We choose the first payment session, as there will only be one active payment session
// This might change in the future.
id: paymentSessions[0].id,
context: { cart_id: cart.id },
provider_token: input.provider_token,
})

const { variants, sales_channel_id } = transform({ cart }, (data) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PaymentCollectionDTO } from "@medusajs/framework/types"
import { PaymentCollectionDTO, PaymentDTO } from "@medusajs/framework/types"
import { MedusaError } from "@medusajs/framework/utils"
import {
WorkflowData,
Expand All @@ -7,11 +7,11 @@ import {
createWorkflow,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../common"
import { capturePaymentWorkflow } from "../../payment"
import {
authorizePaymentSessionStep,
capturePaymentWorkflow,
} from "../../payment"
import { createPaymentSessionsWorkflow } from "../../payment-collection"
createPaymentSessionsWorkflow,
} from "../../payment-collection"

/**
* This step validates that the payment collection is not_paid
Expand Down Expand Up @@ -62,17 +62,16 @@ export const markPaymentCollectionAsPaid = createWorkflow(

const payment = authorizePaymentSessionStep({
id: paymentSession.id,
context: { order_id: input.order_id },
})

capturePaymentWorkflow.runAsStep({
input: {
payment_id: payment.id,
payment_id: payment!.id,
captured_by: input.captured_by,
amount: paymentCollection.amount,
},
})

return new WorkflowResponse(payment)
return new WorkflowResponse<PaymentDTO>(payment!)
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
IPaymentModuleService,
Logger,
PaymentProviderContext,
} from "@medusajs/framework/types"
import { ContainerRegistrationKeys, Modules } from "@medusajs/framework/utils"
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"

export type AuthorizePaymentSessionStepInput = {
id: string
provider_token?: string
context?: PaymentProviderContext
}

export const authorizePaymentSessionStepId = "authorize-payment-session-step"
/**
* This step authorizes a payment session.
*/
export const authorizePaymentSessionStep = createStep(
authorizePaymentSessionStepId,
async (input: AuthorizePaymentSessionStepInput, { container }) => {
const paymentModule = container.resolve<IPaymentModuleService>(
Modules.PAYMENT
)
const payment = await paymentModule.authorizePaymentSession(input.id, {
provider_token: input.provider_token,
context: input.context,
})
return new StepResponse(payment)
},
// If payment or any other part of complete cart fails post payment step, we cancel any payments made
async (payment, { container }) => {
if (!payment) {
return
}

const logger = container.resolve<Logger>(ContainerRegistrationKeys.LOGGER)
const paymentModule = container.resolve<IPaymentModuleService>(
Modules.PAYMENT
)

try {
await paymentModule.cancelPayment(payment.id)
} catch (e) {
logger.error(
`Error was thrown trying to cancel payment - ${payment.id} - ${e}`
)
}
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from "./update-payment-collection"
export * from "./update-refund-reasons"
export * from "./validate-deleted-payment-sessions"
export * from "./cancel-payment-session"
export * from "./authorize-payment-session"
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {
WorkflowData,
WorkflowResponse,
createWorkflow,
} from "@medusajs/framework/workflows-sdk"
import { authorizePaymentSessionStep } from "../steps"

export const authorizePaymentSessionWorkflowId =
"authorize-payment-session-workflow"

/**
* This workflow authorizes a payment session.
*/
export const authorizePaymentSessionWorkflow = createWorkflow(
authorizePaymentSessionWorkflowId,
(input: WorkflowData<{ id: string; provider_token?: string }>) => {
return new WorkflowResponse(authorizePaymentSessionStep(input))
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "./create-refund-reasons"
export * from "./delete-payment-sessions"
export * from "./update-refund-reasons"
export * from "./cancel-payment-session"
export * from "./authorize-payment-session"

This file was deleted.

1 change: 0 additions & 1 deletion packages/core/core-flows/src/payment/steps/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./authorize-payment-session"
export * from "./cancel-payment"
export * from "./capture-payment"
export * from "./refund-payment"
4 changes: 2 additions & 2 deletions packages/core/types/src/payment/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ export interface IPaymentModuleService extends IModuleService {
* @param {string} id - The payment session's ID.
* @param {AuthorizePaymentSessionDTO} data - The attributes to authorize in a payment session.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<PaymentDTO>} The created payment.
* @returns {Promise<PaymentDTO | void>} The created payment or void when authorization is blocked.
*
* @example
* await paymentModuleService.authorizePaymentSession("payses_123", { provider_token: "" })
Expand All @@ -521,7 +521,7 @@ export interface IPaymentModuleService extends IModuleService {
id: string,
data?: AuthorizePaymentSessionDTO,
sharedContext?: Context
): Promise<PaymentDTO>
): Promise<PaymentDTO | void>

/**
* This method cancels a payment session.
Expand Down
20 changes: 11 additions & 9 deletions packages/modules/payment/src/services/payment-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,8 @@ export default class PaymentModuleService
id: string,
data?: AuthorizePaymentSessionDTO,
@MedusaContext() sharedContext?: Context
): Promise<PaymentDTO> {
const paymentSession = await this.paymentSessionService_.retrieve(
): Promise<PaymentDTO | void> {
let paymentSession = await this.paymentSessionService_.retrieve(
id,
{ select: ["data", "context", "provider_id"] },
sharedContext
Expand All @@ -449,13 +449,15 @@ export default class PaymentModuleService
sharedContext
)

const payment = await this.paymentService_.retrieve(
{ payment_session_id: paymentSession.id },
{},
sharedContext
)

return this.baseRepository_.serialize(payment, { populate: true })
paymentSession = await this.paymentSessionService_.retrieve(id, {
relations: ["payment"],
})
if (paymentSession.payment) {
return this.baseRepository_.serialize<PaymentDTO>(
paymentSession.payment,
{ populate: true }
)
}
}

@InjectManager()
Expand Down

0 comments on commit 8b65f89

Please sign in to comment.