docs: improve commerce modules [3/n] (#9510)

Improve and add docs for Order and Payment modules

[3/n]

Closes DOCS-966
Closes #9485
This commit is contained in:
Shahed Nasser
2024-10-14 07:20:35 +00:00
committed by GitHub
parent 74b286b701
commit 11120a8b7e
30 changed files with 662 additions and 314 deletions
@@ -13,16 +13,15 @@ In this guide, youll find common examples of how you can use the Payment Modu
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const paymentModuleService: IPaymentModuleService = req.scope.resolve(
const paymentModuleService = req.scope.resolve(
Modules.PAYMENT
)
@@ -75,16 +74,15 @@ export async function POST(request: Request) {
<CodeTabs groupId="app-type" isCodeCodeTabs={true}>
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const paymentModuleService: IPaymentModuleService = req.scope.resolve(
const paymentModuleService = req.scope.resolve(
Modules.PAYMENT
)
@@ -141,16 +139,15 @@ export async function POST(request: Request) {
<CodeTabs groupId="app-type" isCodeCodeTabs={true}>
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const paymentModuleService: IPaymentModuleService = req.scope.resolve(
const paymentModuleService = req.scope.resolve(
Modules.PAYMENT
)
@@ -195,16 +192,15 @@ export async function POST(request: Request) {
<CodeTabs groupId="app-type" isCodeCodeTabs={true}>
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const paymentModuleService: IPaymentModuleService = req.scope.resolve(
const paymentModuleService = req.scope.resolve(
Modules.PAYMENT
)
@@ -251,16 +247,15 @@ export async function POST(request: Request) {
<CodeTabs groupId="app-type" isCodeCodeTabs={true}>
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const paymentModuleService: IPaymentModuleService = req.scope.resolve(
const paymentModuleService = req.scope.resolve(
Modules.PAYMENT
)
@@ -305,16 +300,15 @@ export async function GET(request: Request) {
<CodeTabs groupId="app-type" isCodeCodeTabs={true}>
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const paymentModuleService: IPaymentModuleService = req.scope.resolve(
const paymentModuleService = req.scope.resolve(
Modules.PAYMENT
)
@@ -0,0 +1,35 @@
export const metadata = {
title: `Links between Payment Module and Other Modules`,
}
# {metadata.title}
This document showcases the module links defined between the Payment Module and other commerce modules.
## Cart Module
The Cart Module provides cart-related features, but not payment processing.
Medusa defines a link between the `Cart` and `PaymentCollection` data models. A cart has a payment collection which holds all the authorized payment sessions and payments made related to the cart.
Learn more about this relation in [this documentation](../payment-collection/page.mdx#usage-with-the-cart-module).
---
## Order Module
An order's payment details are stored in a payment collection. This also applies for claims and exchanges.
So, Medusa defines links between the `PaymentCollection` data model and the `Order`, `OrderClaim`, and `OrderExchange` data models.
![A diagram showcasing an example of how data models from the Order and Payment modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1716554726/Medusa%20Resources/order-payment_ubdwok.jpg)
---
## Region Module
You can specify for each region which payment providers are available. The Medusa application defines a link between the `PaymentProvider` and the `Region` data models.
![A diagram showcasing an example of how resources from the Payment and Region modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1711569520/Medusa%20Resources/payment-region_jyo2dz.jpg)
This increases the flexibility of your store. For example, you only show during checkout the payment providers associated with the cart's region.
@@ -17,8 +17,8 @@ In this document, you'll learn about the options of the Payment Module.
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Option</Table.HeaderCell>
<Table.HeaderCell>Description</Table.HeaderCell>
<Table.HeaderCell className="w-1/4">Option</Table.HeaderCell>
<Table.HeaderCell className="w-2/4">Description</Table.HeaderCell>
<Table.HeaderCell>Required</Table.HeaderCell>
<Table.HeaderCell>Default</Table.HeaderCell>
</Table.Row>
@@ -93,7 +93,9 @@ In this document, you'll learn about the options of the Payment Module.
</Table.Body>
</Table>
## providers
---
## providers Option
The `providers` option is an array of payment module providers.
@@ -7,7 +7,7 @@ export const metadata = {
# {metadata.title}
The Payment Module is the `@medusajs/medusa/payment` NPM package that provides payment-related features in your Medusa and Node.js applications.
The Payment Module provides payment-related features in your Medusa and Node.js applications.
## How to Use Payment Module's Service
@@ -16,18 +16,34 @@ You can use the Payment Module's main service by resolving from the Medusa conta
For example:
<CodeTabs groupId="resource-type">
<CodeTab label="Workflow Step" value="workflow-step">
```ts title="src/workflows/hello-world/step1.ts"
import { createStep } from "@medusajs/framework/workflows-sdk"
import { Modules } from "@medusajs/framework/utils"
const step1 = createStep("step-1", async (_, { container }) => {
const paymentModuleService = container.resolve(
Modules.PAYMENT
)
const payment_collections =
await paymentModuleService.listPaymentCollections()
})
```
</CodeTab>
<CodeTab label="API Route" value="api-route">
```ts title="src/api/store/custom/route.ts"
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
```ts title="src/api/store/custom/route.ts"
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const paymentModuleService: IPaymentModuleService = req.scope.resolve(
const paymentModuleService = req.scope.resolve(
Modules.PAYMENT
)
@@ -40,37 +56,18 @@ export async function GET(
</CodeTab>
<CodeTab label="Subscriber" value="subscribers">
```ts title="src/subscribers/custom-handler.ts"
import { SubscriberArgs } from "@medusajs/framework"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
```ts title="src/subscribers/custom-handler.ts"
import { SubscriberArgs } from "@medusajs/framework"
import { Modules } from "@medusajs/framework/utils"
export default async function subscriberHandler({ container }: SubscriberArgs) {
const paymentModuleService: IPaymentModuleService = container.resolve(
const paymentModuleService = container.resolve(
Modules.PAYMENT
)
const payment_collections =
await paymentModuleService.listPaymentCollections()
}
```
</CodeTab>
<CodeTab label="Workflow Step" value="workflow-step">
```ts title="src/workflows/hello-world/step1.ts"
import { createStep } from "@medusajs/framework/workflows-sdk"
import { IPaymentModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
const step1 = createStep("step-1", async (_, { container }) => {
const paymentModuleService: IPaymentModuleService = container.resolve(
Modules.PAYMENT
)
const payment_collections =
await paymentModuleService.listPaymentCollections()
})
```
</CodeTab>
@@ -84,7 +81,7 @@ const step1 = createStep("step-1", async (_, { container }) => {
The Payment Module provides payment functionalities that allow you to process payment of any resource, such as a cart.
All payment processing starts with creating a payment collection.
All payment processing starts with creating a payment collection, which carries information for authorized, captured, and refunded payments for a single resource.
```ts
const paymentCollection = await paymentModuleService.createPaymentCollections({
@@ -96,7 +93,7 @@ const paymentCollection = await paymentModuleService.createPaymentCollections({
### Authorize, Capture, and Refund Payment
The Payment Module provides essential features to receive and handle payments, including authorizing, capturing, and refunding payment.
Receive and handle payments, including authorizing, capturing, and refunding payment.
```ts
await paymentModuleService.capturePayment({
@@ -4,7 +4,7 @@ export const metadata = {
# {metadata.title}
In this document, youll learn what a payment collection is and how to use it with the Cart Module.
In this document, youll learn what a payment collection is and how the Medusa application uses it with the Cart Module.
## What's a Payment Collection?
@@ -12,15 +12,17 @@ A payment collection stores payment details related to a resource, such as a car
Every purchase or request for payment starts with a payment collection. The collection holds details necessary to complete the payment, including:
- The payment sessions that represents the payment amount to authorize.
- The payments that are created when a payment session is authorized. They can be captured and refunded.
- The payment providers that handle the processing of each payment session, including the authorization, capture, and refund.
- The [payment sessions](../payment-session/page.mdx) that represents the payment amount to authorize.
- The [payments](../payment/page.mdx) that are created when a payment session is authorized. They can be captured and refunded.
- The [payment providers](../payment-provider/page.mdx) that handle the processing of each payment session, including the authorization, capture, and refund.
---
## Multiple Payments
The payment collection supports multiple payment sessions and payments. You can use this to accept payments in increments or split payments across payment providers.
The payment collection supports multiple payment sessions and payments.
You can use this to accept payments in increments or split payments across payment providers.
![Diagram showcasing how a payment collection can have multiple payment sessions and payments](https://res.cloudinary.com/dza7lstvk/image/upload/v1711554695/Medusa%20Resources/payment-collection-multiple-payments_oi3z3n.jpg)
@@ -30,8 +32,8 @@ The payment collection supports multiple payment sessions and payments. You can
The Cart Module provides cart management features. However, it doesnt provide any features related to accepting payment.
With the Payment Module, you can create a payment collection for the cart and process the payment.
During checkout, the Medusa application links a cart to a payment collection, which will be used for further payment processing.
The Medusa application creates a link between the `PaymentCollection` and `Cart` data models. It also implements the payment flow during checkout as explained in [this documentation](../payment-flow/page.mdx).
It also implements the payment flow during checkout as explained in [this documentation](../payment-flow/page.mdx).
![Diagram showcasing the relation between the Payment and Cart modules](https://res.cloudinary.com/dza7lstvk/image/upload/v1711537849/Medusa%20Resources/cart-payment_ixziqm.jpg)
@@ -4,7 +4,13 @@ export const metadata = {
# {metadata.title}
In this document, youll learn how to implement an accept-payment flow.
In this document, youll learn how to implement an accept-payment flow using the Payment Module's main service.
<Note title="Tip">
For a guide on how to implement this flow in the storefront, check out [this guide](../../../storefront-development/checkout/payment/page.mdx).
</Note>
## Flow Overview
@@ -14,7 +20,7 @@ In this document, youll learn how to implement an accept-payment flow.
## 1. Create a Payment Collection
The payment collection holds all details related to a resources payment operations. So, you start off by creating a payment collection.
A payment collection holds all details related to a resources payment operations. So, you start off by creating a payment collection.
For example:
@@ -27,14 +33,43 @@ const paymentCollection =
})
```
You can then link the payment collection to another resource, such as a cart in the Cart Module.
<Note>
<Note title="Tip">
Learn more about the `createPaymentCollections` method in [this reference](/references/payment/createPaymentCollections).
</Note>
Then, create a link between the payment collection and the resource it's storing payment details for, such as a cart in the Cart Module:
```ts
import {
ContainerRegistrationKeys,
Modules
} from "@medusajs/framework/utils"
// ...
// resolve the remote link
const remoteLink = container.resolve(
ContainerRegistrationKeys
)
remoteLink.create({
[Modules.CART]: {
cart_id: "cart_123"
},
[Modules.PAYMENT]: {
payment_collection_id: paymentCollection.id
}
})
```
<Note title="Tip">
Learn more about the remote link in [this documentation](!docs!/advanced-development/module-links/remote-link).
</Note>
---
## 2. Create Payment Sessions
@@ -61,8 +96,6 @@ const paymentSession =
)
```
You can also create payment sessions for every supported payment provider to allow customers to choose from them.
<Note>
Learn more about the `createPaymentSession` method in [this reference](/references/payment/createPaymentSession).
@@ -95,9 +128,9 @@ Learn more about the `authorizePaymentSession` method in [this reference](/refer
### Handling Additional Action
If the payment authorization isnt successful, either because it requires additional action or for another reason, the method updates the payment session with the new status and throws an error.
If the payment authorization isnt successful, whether because it requires additional action or for another reason, the method updates the payment session with the new status and throws an error.
In that case, you can catch that error and, if there are required actions, handle them accordingly, then retry the authorization.
In that case, you can catch that error and, if the session's `status` property is `requires_more`, handle the additional action, then retry the authorization.
For example:
@@ -10,7 +10,7 @@ In this document, youll learn what a payment module provider is.
## What's a Payment Module Provider?
A payment module provider registers a payment provider that handles payment processing. It can integrate third-party payment providers, such as Stripe.
A payment module provider registers a payment provider that handles payment processing in the Medusa application. It integrates third-party payment providers, such as Stripe.
To authorize a payment amount with a payment provider, a payment session is created and associated with that payment provider. The payment provider is then used to handle the authorization.
@@ -24,20 +24,18 @@ After the payment session is authorized, the payment provider is associated with
## System Payment Provider
The Payment Module provides a `system` payment provider that acts as a placeholder payment provider. It doesnt handle payment processing and delegates that to the merchant. It acts similarly to a cash-on-delivery (COD) payment method.
The Payment Module provides a `system` payment provider that acts as a placeholder payment provider.
It doesnt handle payment processing and delegates that to the merchant. It acts similarly to a cash-on-delivery (COD) payment method.
---
## How are Payment Providers Created?
A payment provider is a TypeScript or JavaScript class that extends the `AbstractPaymentProvider` imported from `@medusajs/framework/utils`. It can then be exported as the main service of a module.
<Note title="Tip">
A payment provider is a module whose main service extends the `AbstractPaymentProvider` imported from `@medusajs/framework/utils`.
Refer to [this guide](/references/payment/provider) on how to create a payment provider for the Payment Module.
</Note>
---
## Configure Payment Providers
@@ -50,4 +48,6 @@ Learn more about this option in [this documentation](../module-options/page.mdx#
## PaymentProvider Data Model
When the Medusa application starts and registers the payment providers, it also creates a record of the `PaymentProvider` data model if none exists. This data model is used to reference a payment provider and determine whether its installed in the application.
When the Medusa application starts and registers the payment providers, it also creates a record of the `PaymentProvider` data model if none exists.
This data model is used to reference a payment provider and determine whether its installed in the application.
@@ -12,14 +12,6 @@ export const metadata = {
In this document, youll learn about the Stripe Module Provider and how to install and use it in the Payment Module.
## Features
[Stripe](https://stripe.com/) is a battle-tested and unified platform for transaction handling. Stripe supplies you with the technical components needed to handle transactions safely and all the analytical features necessary to gain insight into your sales.
These features are also available in a safe test environment, allowing for a concern-free development process.
---
## Register the Stripe Module Provider
<Prerequisites items={[
@@ -103,7 +95,7 @@ STRIPE_API_KEY=<YOUR_STRIPE_API_KEY>
</Table.Cell>
<Table.Cell>
-
\-
</Table.Cell>
</Table.Row>
@@ -125,7 +117,7 @@ STRIPE_API_KEY=<YOUR_STRIPE_API_KEY>
</Table.Cell>
<Table.Cell>
-
\-
</Table.Cell>
</Table.Row>
@@ -198,6 +190,8 @@ STRIPE_API_KEY=<YOUR_STRIPE_API_KEY>
</Table.Body>
</Table>
---
## Use Provider
To use the Stripe provider, create a payment session for the provider:
@@ -217,3 +211,9 @@ const paymentSession =
}
)
```
---
## Useful Guides
- [Storefront guide: Add Stripe payment method during checkout](../../../../storefront-development/checkout/payment/stripe/page.mdx).
@@ -10,7 +10,7 @@ In this document, youll learn what a payment session is.
A payment session, represented by the [PaymentSession data model](/references/payment/modules/PaymentSession), is a payment amount to be authorized. Its associated with a payment provider that handles authorizing it.
A payment collection can have multiple payment sessions. For example, during checkout, when a customer chooses between paying with Stripe or PayPal, each of these payment options is a payment session associated with a payment provider (Stripe or PayPal).
A payment collection can have multiple payment sessions. Using this feature, you can implement payment in installments or payments using multiple providers.
![Diagram showcasing how every payment session has a different payment provider](https://res.cloudinary.com/dza7lstvk/image/upload/v1711565056/Medusa%20Resources/payment-session-provider_guxzqt.jpg)
@@ -10,7 +10,7 @@ In this document, youll learn what a payment is and how it's created, capture
When a payment session is authorized, a payment, represented by the [Payment data model](/references/payment/models/Payment), is created. This payment can later be captured or refunded.
A payment carries along many of the data and relations of a payment session:
A payment carries many of the data and relations of a payment session:
- It belongs to the same payment collection.
- Its associated with the same payment provider, which handles further payment processing.
@@ -1,33 +0,0 @@
export const metadata = {
title: `Relations between Payment Module and Other Modules`,
}
# {metadata.title}
This document showcases the link modules defined between the Payment Module and other commerce modules.
## Cart Module
The Payment Module can be used with the Cart Module to accept payment for the cart during checkout.
Learn more about this relation in [this documentation](../payment-collection/page.mdx#usage-with-the-cart-module).
---
## Order Module
An order's payment is stored in a payment collection. Medusa defines a link module that builds a relationship between the `Order` and `PaymentCollection` data models.
![A diagram showcasing an example of how data models from the Order and Payment modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1716554726/Medusa%20Resources/order-payment_ubdwok.jpg)
---
## Region Module
You can specify for each region which payment providers are available. The Medusa application forms a relation between the `PaymentProvider` and the `Region` data models.
![A diagram showcasing an example of how resources from the Payment and Region modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1711569520/Medusa%20Resources/payment-region_jyo2dz.jpg)
This increases the flexibility of your store.
For example, paired with other modules, such as the Cart Module, you only show during checkout the payment providers associated with the cart's region.
@@ -8,15 +8,17 @@ In this document, youll learn how the Payment Module supports listening to we
## What's a Webhook Event?
A webhook event is sent from a third-party payment provider to your application. It indicates a change in a payments status. This is useful in different cases such as when a payment is being processed asynchronously or when a request is interrupted.
A webhook event is sent from a third-party payment provider to your application. It indicates a change in a payments status.
This is useful in many cases such as when a payment is being processed asynchronously or when a request is interrupted and the payment provider is sending details on the process later.
---
## processEvent Method
The Payment Modules main service (`IPaymentModuleService`) provides a [processEvent method](/references/payment/processEvent) used to handle incoming webhook events from third-party payment services. The method delegates the handling to the associated payment provider, which returns the event's details.
The Payment Modules main service has a [processEvent method](/references/payment/processEvent) used to handle incoming webhook events from third-party payment services. The method delegates the handling to the associated payment provider, which returns the event's details.
Medusa implements a webhook listener at the `/hooks/payment/[provider]` API route, where `[provider]` is the ID of the provider (for example, `stripe`). You can use that webhook listener in your third-party payment provider's configurations.
Medusa implements a webhook listener route at the `/hooks/payment/[provider]` API route, where `[provider]` is the ID of the provider (for example, `stripe`). Use that webhook listener in your third-party payment provider's configurations.
![A diagram showcasing the steps of how the processEvent method words](https://res.cloudinary.com/dza7lstvk/image/upload/v1711567415/Medusa%20Resources/payment-webhook_seaocg.jpg)