docs: revise commerce modules overview pages (#10738)

* revise API Key Module overview

* revise auth module

* support ref sidebar items

* remove examples

* revise cart module

* revise currency

* revise customer module

* revise fulfillment module

* revise inventory module

* revise order module

* revise payment

* revise pricing module

* revise product module

* revise promotion module

* revise region module

* revise sales channel module

* revise stock location module

* revise store module

* revise tax module

* revise user module

* lint content + fix snippets
This commit is contained in:
Shahed Nasser authored and GitHub committed 2024-12-26 10:32:16 +02:00
1 parent c8f9938865
commit ebca8fed28
112 files changed
+9465 -7731

No files matched your search

@@ -1,526 +0,0 @@
import { CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `Examples of the Inventory Module`,
}
# {metadata.title}
In this document, you’ll find common examples of how you can use the Inventory Module in your application.
<Note>
You should only use the Inventory Module's main service when implementing complex customizations. For common cases, check out [available workflows instead](../../../medusa-workflows-reference/page.mdx).
</Note>
## Create an Inventory Item
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
const inventoryItem = await inventoryModuleService.createInventoryItems({
sku: request.body.sku,
title: request.body.title,
requires_shipping: request.body.requires_shipping,
})
res.json({ inventory_item: inventoryItem })
}
```
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeInventoryModule } from "@medusajs/medusa/inventory"
export async function POST(request: Request) {
const inventoryModuleService = await initializeInventoryModule({})
const body = await request.json()
const inventoryItem = await inventoryModuleService.createInventoryItems({
sku: body.sku,
title: body.title,
requires_shipping: body.requires_shipping,
})
return NextResponse.json({ inventory_item: inventoryItem })
}
```
</CodeTab>
</CodeTabs>
---
## List Inventory Items
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
const inventoryItems = await inventoryModuleService.listInventoryItems({})
res.json({ inventory_items: inventoryItems })
}
```
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeInventoryModule } from "@medusajs/medusa/inventory"
export async function GET(request: Request) {
const inventoryModuleService = await initializeInventoryModule({})
const inventoryItems = await inventoryModuleService.listInventoryItems({})
return NextResponse.json({ inventory_items: inventoryItems })
}
```
</CodeTab>
</CodeTabs>
---
## Retrieve an Inventory Item by its ID
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
const inventoryItem = await inventoryModuleService.retrieveInventoryItem(
request.params.id
)
res.json({ inventory_item: inventoryItem })
}
```
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeInventoryModule } from "@medusajs/medusa/inventory"
type ContextType = {
params: {
id: string
}
}
export async function GET(request: Request, { params }: ContextType) {
const inventoryModuleService = await initializeInventoryModule({})
const inventoryItem = await inventoryModuleService.retrieveInventoryItem(
params.id
)
return NextResponse.json({ inventory_item: inventoryItem })
}
```
</CodeTab>
</CodeTabs>
---
## Create an Inventory Level
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
const inventoryLevel = await inventoryModuleService.createInventoryLevels({
inventory_item_id: request.body.inventory_item_id,
location_id: request.body.location_id,
stocked_quantity: request.body.quantity,
})
res.json({ inventory_level: inventoryLevel })
}
```
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeInventoryModule } from "@medusajs/medusa/inventory"
export async function POST(request: Request) {
const inventoryModuleService = await initializeInventoryModule({})
const body = await request.json()
const inventoryLevel = await inventoryModuleService.createInventoryLevels({
inventory_item_id: body.inventory_item_id,
location_id: body.location_id,
stocked_quantity: body.quantity,
})
return NextResponse.json({ inventory_level: inventoryLevel })
}
```
</CodeTab>
</CodeTabs>
---
## Adjust Inventory in Location
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
const inventoryLevel = await inventoryModuleService.adjustInventory(
request.body.inventory_item_id,
request.body.location_id,
request.body.new_quantity
)
res.json({ inventory_level: inventoryLevel })
}
```
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeInventoryModule } from "@medusajs/medusa/inventory"
export async function POST(request: Request) {
const inventoryModuleService = await initializeInventoryModule({})
const body = await request.json()
const inventoryLevel = await inventoryModuleService.adjustInventory(
body.inventory_item_id,
body.location_id,
body.new_quantity
)
return NextResponse.json({ inventory_level: inventoryLevel })
}
```
</CodeTab>
</CodeTabs>
---
## Confirm Inventory Item Availability
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
res.json({
is_available: await inventoryModuleService.confirmInventory(
request.body.inventory_item_id,
[request.body.location_id],
request.body.required_quantity
),
})
}
```
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeInventoryModule } from "@medusajs/medusa/inventory"
export async function POST(request: Request) {
const inventoryModuleService = await initializeInventoryModule({})
const body = await request.json()
return NextResponse.json({
is_available: await inventoryModuleService.confirmInventory(
body.inventory_item_id,
[body.location_id],
body.required_quantity
),
})
}
```
</CodeTab>
</CodeTabs>
---
## Create Reservation Item
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
const reservationItem = await inventoryModuleService.createReservationItems({
inventory_item_id: request.body.inventory_item_id,
location_id: request.body.location_id,
quantity: request.body.reserved_quantity,
})
res.json({ reservation_item: reservationItem })
}
```
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeInventoryModule } from "@medusajs/medusa/inventory"
export async function POST(request: Request) {
const inventoryModuleService = await initializeInventoryModule({})
const body = await request.json()
const reservationItem = await inventoryModuleService.createReservationItems({
inventory_item_id: body.inventory_item_id,
location_id: body.location_id,
quantity: body.reserved_quantity,
})
return NextResponse.json({
reservation_item: reservationItem,
})
}
```
</CodeTab>
</CodeTabs>
---
## Retrieve Quantity Details
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
const reservedQuantity =
await inventoryModuleService.retrieveReservedQuantity(
request.params.inventory_item_id,
[request.params.location_id]
)
const stockedQuantity = await inventoryModuleService.retrieveStockedQuantity(
request.params.inventory_item_id,
[request.params.location_id]
)
const availableQuantity =
await inventoryModuleService.retrieveAvailableQuantity(
request.params.inventory_item_id,
[request.params.location_id]
)
res.json({
reserved_quantity: reservedQuantity,
stocked_quantity: stockedQuantity,
available_quantity: availableQuantity,
})
}
```
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeInventoryModule } from "@medusajs/medusa/inventory"
type ContextType = {
params: {
inventory_item_id: string
location_id: string
}
}
export async function POST(request: Request, { params }: ContextType) {
const inventoryModuleService = await initializeInventoryModule({})
const reservedQuantity =
await inventoryModuleService.retrieveReservedQuantity(
params.inventory_item_id,
[params.location_id]
)
const stockedQuantity = await inventoryModuleService.retrieveStockedQuantity(
params.inventory_item_id,
[params.location_id]
)
const availableQuantity =
await inventoryModuleService.retrieveAvailableQuantity(
params.inventory_item_id,
[params.location_id]
)
return NextResponse.json({
reserved_quantity: reservedQuantity,
stocked_quantity: stockedQuantity,
available_quantity: availableQuantity,
})
}
```
</CodeTab>
</CodeTabs>
---
## Delete a Reservation
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function DELETE(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
await inventoryModuleService.deleteReservationItems([
request.params.reservation_id,
])
res.status(200)
}
```
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
import { initialize as initializeInventoryModule } from "@medusajs/medusa/inventory"
type ContextType = {
params: {
reservation_id: string
}
}
export async function DELETE(request: Request, { params }: ContextType) {
const inventoryModuleService = await initializeInventoryModule({})
await inventoryModuleService.deleteReservationItems([params.reservation_id])
}
```
</CodeTab>
</CodeTabs>
---
## More Examples
The [Inventory Module's main service reference](/references/inventory-next) provides a reference to all the methods available for use with examples for each.
@@ -42,8 +42,8 @@ To retrieve the product variants of an inventory item with [Query](!docs!/learn/
const { data: inventoryItems } = await query.graph({
entity: "inventory_item",
fields: [
"variants.*"
]
"variants.*",
],
})
// inventoryItems.variants
@@ -60,8 +60,8 @@ import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
const { data: inventoryItems } = useQueryGraphStep({
entity: "inventory_item",
fields: [
"variants.*"
]
"variants.*",
],
})
// inventoryItems.variants
@@ -131,8 +131,8 @@ To retrieve the stock locations of an inventory level with [Query](!docs!/learn/
const { data: inventoryLevels } = await query.graph({
entity: "inventory_level",
fields: [
"stock_locations.*"
]
"stock_locations.*",
],
})
// inventoryLevels.stock_locations
@@ -149,8 +149,8 @@ import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
const { data: inventoryLevels } = useQueryGraphStep({
entity: "inventory_level",
fields: [
"stock_locations.*"
]
"stock_locations.*",
],
})
// inventoryLevels.stock_locations
@@ -6,130 +6,156 @@ export const metadata = {
# {metadata.title}
The Inventory Module provides inventory-related features in your Medusa and Node.js applications.
In this section of the documentation, you will find resources to learn more about the Inventory Module and how to use it in your application.
## How to Use Inventory Module's Service
Medusa has inventory related features available out-of-the-box through the Inventory Module. A [module](!docs!/learn/fundamentals/modules) is a standalone package that provides features for a single domain. Each of Medusa's commerce features are placed in commerce modules, such as this Inventory Module.
You can use the Inventory Module's main service by resolving from the Medusa container the resource `Modules.INVENTORY`.
<Note>
Learn more about why modules are isolated in [this documentation](!docs!/learn/fundamentals/modules/isolation).
</Note>
## Inventory Features
- [Inventory Items Management](./concepts/page.mdx): Store and manage inventory of any stock-kept item, such as product variants.
- [Inventory Across Locations](./concepts/page.mdx#inventorylevel): Manage inventory levels across different locations, such as warehouses.
- [Reservation Management](./concepts/page.mdx#reservationitem): Reserve quantities of inventory items at specific locations for orders or other purposes.
- [Check Inventory Availability](/references/inventory-next/confirmInventory): Check whether an inventory item has the necessary quantity for purchase.
---
## How to Use the Inventory Module
In your Medusa application, you build flows around commerce modules. A flow is built as a [Workflow](!docs!/learn/fundamentals/workflows), which is a special function composed of a series of steps that guarantees data consistency and reliable roll-back mechanism.
You can build custom workflows and steps. You can also re-use Medusa's workflows and steps, which are provided by the `@medusajs/medusa/core-flows` package.
For example:
<CodeTabs groupId="resource-type">
<CodeTab label="Workflow Step" value="workflow-step">
export const highlights = [
["12", "Modules.INVENTORY", "Resolve the module in a step."]
]
```ts title="src/workflows/hello-world/step1.ts"
import { createStep } from "@medusajs/framework/workflows-sdk"
```ts title="src/workflows/create-inventory-item.ts" highlights={highlights}
import {
createWorkflow,
WorkflowResponse,
createStep,
StepResponse,
} from "@medusajs/framework/workflows-sdk"
import { Modules } from "@medusajs/framework/utils"
const step1 = createStep("step-1", async (_, { container }) => {
const inventoryModuleService = container.resolve(
Modules.INVENTORY
)
const createInventoryItemStep = createStep(
"create-inventory-item",
async ({}, { container }) => {
const inventoryModuleService = container.resolve(Modules.INVENTORY)
const inventoryItems = await inventoryModuleService.listInventoryItems({})
})
const inventoryItem = await inventoryModuleService.createInventoryItems({
sku: "SHIRT",
title: "Green Medusa Shirt",
requires_shipping: true,
})
return new StepResponse({ inventoryItem }, inventoryItem.id)
},
async (inventoryItemId, { container }) => {
if (!inventoryItemId) {
return
}
const inventoryModuleService = container.resolve(Modules.INVENTORY)
await inventoryModuleService.deleteInventoryItems([inventoryItemId])
}
)
export const createInventoryItemWorkflow = createWorkflow(
"create-inventory-item-workflow",
() => {
const { inventoryItem } = createInventoryItemStep()
return new WorkflowResponse({
inventoryItem,
})
}
)
```
</CodeTab>
<CodeTab label="API Route" value="api-route">
You can then execute the workflow in your custom API routes, scheduled jobs, or subscribers:
```ts title="src/api/store/custom/route.ts"
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
<CodeTabs group="resource-types">
<CodeTab label="API Route" value="api-route">
```ts title="src/api/workflow/route.ts" highlights={[["11"], ["12"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
import { createInventoryItemWorkflow } from "../../workflows/create-inventory-item"
export async function GET(
request: MedusaRequest,
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const inventoryModuleService = request.scope.resolve(
Modules.INVENTORY
)
) {
const { result } = await createInventoryItemWorkflow(req.scope)
.run()
res.json({
inventory_items: await inventoryModuleService.listInventoryItems({}),
})
res.send(result)
}
```
</CodeTab>
<CodeTab label="Subscriber" value="subscribers">
<CodeTab label="Subscriber" value="subscriber">
```ts title="src/subscribers/user-created.ts" highlights={[["11"], ["12"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import {
type SubscriberConfig,
type SubscriberArgs,
} from "@medusajs/framework"
import { createInventoryItemWorkflow } from "../workflows/create-inventory-item"
```ts title="src/subscribers/custom-handler.ts"
import { SubscriberArgs } from "@medusajs/framework"
import { Modules } from "@medusajs/framework/utils"
export default async function handleUserCreated({
event: { data },
container,
}: SubscriberArgs<{ id: string }>) {
const { result } = await createInventoryItemWorkflow(container)
.run()
export default async function subscriberHandler({ container }: SubscriberArgs) {
const inventoryModuleService = container.resolve(
Modules.INVENTORY
)
console.log(result)
}
const inventoryItems = await inventoryModuleService.listInventoryItems({})
export const config: SubscriberConfig = {
event: "user.created",
}
```
</CodeTab>
<CodeTab label="Scheduled Job" value="scheduled-job">
```ts title="src/jobs/run-daily.ts" highlights={[["7"], ["8"]]}
import { MedusaContainer } from "@medusajs/framework/types"
import { createInventoryItemWorkflow } from "../workflows/create-inventory-item"
export default async function myCustomJob(
container: MedusaContainer
) {
const { result } = await createInventoryItemWorkflow(container)
.run()
console.log(result)
}
export const config = {
name: "run-once-a-day",
schedule: `0 0 * * *`,
}
```
</CodeTab>
</CodeTabs>
Learn more about workflows in [this documentation](!docs!/learn/fundamentals/workflows).
---
## Features
### Inventory Items Management
Store and manage inventory of any stock-kept item, such as product variants.
Inventory items hold details of the underlying stock-kept item, as well as inventory details such as whether the item requires shipping.
```ts
const inventoryItem = await inventoryModuleService.createInventoryItems({
sku: "SHIRT",
title: "Green Medusa Shirt",
requires_shipping: true,
})
```
### Inventory Across Locations
Inventory items' quantities are set per locations through inventory levels.
This gives you more flexibility in managing the quantity of a stock-kept item across different locations, such as different warehouses.
```ts
const inventoryLevel = await inventoryModuleService.createInventoryLevels([
{
inventory_item_id: "iitem_123",
location_id: "sloc_123",
stocked_quantity: 20,
},
])
```
### Reservation Management
Reserve quantities of inventory items at specific locations for orders or other purposes.
The reserved quantity isn't considered for purchase, but can be deleted to revert the reservation.
```ts
const reservationItem = await inventoryModuleService.createReservationItems([
{
inventory_item_id: "iitem_123",
location_id: "sloc_123",
quantity: 10,
},
])
```
### Check Inventory Availability
Check whether an inventory item has the necessary quantity for purchase.
Any reserved quantity is considered unavailable.
```ts
const isAvailable = await inventoryModuleService.confirmInventory(
inventoryItemId,
[locationId],
neededQuantity
)
```
<CommerceModuleSections name="Inventory" />