docs: add notes + missing links for user guide (#11621)

* docs: add notes + missing links for user guide

* fix build errors

* fixes
This commit is contained in:
Shahed Nasser authored and GitHub committed 2025-02-26 15:28:18 +02:00
1 parent 322d108c03
commit 95eef899f7
76 files changed
+736 -794

No files matched your search

+116 -60
View File
@@ -34,12 +34,20 @@ Use sales channels to set product availability per channel. In this case, create
You can create a sales channel through the Medusa Admin or Admin REST APIs.
<Card
href="!api!/admin#sales-channels_postsaleschannels"
title="Create Sales Channel"
text="Create the sales channel using the REST APIs."
icon={AcademicCapSolid}
/>
<CardList items={[
{
href: "!user-guide!/settings/sales-channels",
title: "Using Medusa Admin",
text: "Create the sales channel using the Medusa Admin.",
icon: UsersSolid,
},
{
href: "!api!/admin#sales-channels_postsaleschannels",
title: "Using Admin API",
text: "Create the sales channel using the REST APIs.",
icon: AcademicCapSolid,
},
]} />
---
@@ -56,21 +64,37 @@ You can create a publishable API key through the Medusa Admin or the Admin REST
### Create Key
<Card
href="!api!/admin#api-keys_postapikeys"
title="Create Publishable API Key"
text="Create the publishable API key using the REST APIs."
icon={AcademicCapSolid}
/>
<CardList items={[
{
href: "!user-guide!/settings/developer/publishable-api-keys",
title: "Using Medusa Admin",
text: "Create the API key using the Medusa Admin.",
icon: UsersSolid,
},
{
href: "!api!/admin#api-keys_postapikeys",
title: "Using Admin API",
text: "Create the API key using the REST APIs.",
icon: AcademicCapSolid,
},
]} />
### Associate Key with Sales Channel
<Card
href="!api!/admin#api-keys_postapikeysidsaleschannels"
title="Create Publishable API Key"
text="Create the publishable API key using the REST APIs."
icon={AcademicCapSolid}
/>
<CardList items={[
{
href: "!user-guide!/settings/developer/publishable-api-keys#manage-publishable-api-keys-sales-channels",
title: "Using Medusa Admin",
text: "Associate the key with the sales channel using the Medusa Admin.",
icon: UsersSolid,
},
{
href: "!api!/admin#api-keys_postapikeysidsaleschannels",
title: "Using Admin API",
text: "Associate the key with the sales channel using the REST APIs.",
icon: AcademicCapSolid,
},
]} />
---
@@ -80,21 +104,37 @@ You can create new products or add existing ones to the B2B sales channel using
### Create Products
<Card
href="!api!/admin#products_postproducts"
title="Create Products"
text="Create products using the REST APIs."
icon={AcademicCapSolid}
/>
<CardList items={[
{
href: "!user-guide!/products/create",
title: "Using Medusa Admin",
text: "Create the products using the Medusa Admin.",
icon: UsersSolid,
},
{
href: "!api!/admin#products_postproducts",
title: "Using Admin API",
text: "Create the products using the REST APIs.",
icon: AcademicCapSolid,
},
]} />
### Add Products to Sales Channel
<Card
href="!api!/admin#sales-channels_postsaleschannelsidproductsbatchadd"
title="Add to Sales Channel"
text="Add the products to the B2B sales channel using the REST APIs."
icon={AcademicCapSolid}
/>
<CardList items={[
{
href: "!user-guide!/settings/sales-channels#manage-products-in-sales-channel",
title: "Using Medusa Admin",
text: "Create the products using the Medusa Admin.",
icon: UsersSolid,
},
{
href: "!api!/admin#sales-channels_postsaleschannelsidproductsbatchadd",
title: "Using Admin API",
text: "Add the products to the sales channel using the REST APIs.",
icon: AcademicCapSolid,
},
]} />
---
@@ -110,25 +150,17 @@ You can create a B2B module that adds necessary data models to represent a B2B c
{
href: "!docs!/learn/fundamentals/modules",
title: "Create Module",
text: "Learn how to create a module in Medusa.",
text: "Learn how to create a module.",
icon: AcademicCapSolid,
},
{
href: "!docs!/learn/fundamentals/modules#1-create-data-model",
title: "Create Data Models",
text: "Learn how to create data models.",
href: "!docs!/learn/fundamentals/module-links",
title: "Define Module Links",
text: "Define links between data models.",
icon: AcademicCapSolid,
},
]} />
<Card
href="!docs!/learn/fundamentals/module-links"
title="Create Module Links"
text="Learn how to create links between modules."
icon={AcademicCapSolid}
className="mt-1"
/>
## Add B2B Customers
After adding your B2B customer group, add B2B customers and assign them to the B2B customer group.
@@ -137,21 +169,37 @@ You can do that through the Medusa Admin or Admin REST APIs.
### Create Customers
<Card
href="!api!/admin#customers_postcustomers"
title="Create Customers"
text="Create the customers using the REST APIs."
icon={AcademicCapSolid}
/>
<CardList items={[
{
href: "!user-guide!/customers/manage",
title: "Using Medusa Admin",
text: "Create customers using the Medusa Admin.",
icon: UsersSolid,
},
{
href: "!api!/admin#customers_postcustomers",
title: "Using Admin API",
text: "Create customers using the REST APIs.",
icon: AcademicCapSolid,
},
]} />
### Assign Customers to Groups
<Card
href="!api!/admin#customer-groups_postcustomergroupsidcustomersbatch"
title="Assign Customers to Groups"
text="Assign the customers to the B2B customer group using the REST APIs."
icon={AcademicCapSolid}
/>
<CardList items={[
{
href: "!user-guide!/customers/manage#manage-customers-groups",
title: "Using Medusa Admin",
text: "Assign customer to groups using the Medusa Admin.",
icon: UsersSolid,
},
{
href: "!api!/admin#customer-groups_postcustomergroupsidcustomersbatch",
title: "Using Admin API",
text: "Assign customer to groups using the REST APIs.",
icon: AcademicCapSolid,
},
]} />
---
@@ -161,12 +209,20 @@ Use price lists to set different prices for each B2B customer group, among other
You can create a price list using the Medusa Admin or the Admin REST APIs. Make sure to set the B2B customer group as a condition.
<Card
href="!api!/admin#price-lists_postpricelists"
title="Create Price List"
text="Create the price list using the REST APIs."
icon={AcademicCapSolid}
/>
<CardList items={[
{
href: "!user-guide!/price-lists/create",
title: "Using Medusa Admin",
text: "Create price list using the Medusa Admin.",
icon: UsersSolid,
},
{
href: "!api!/admin#price-lists_postpricelists",
title: "Using Admin API",
text: "Create price list using the REST APIs.",
icon: AcademicCapSolid,
},
]} />
---
@@ -1,11 +1,10 @@
import { AcademicCapSolid, BoltSolid } from "@medusajs/icons"
import { BetaBadge } from "docs-ui"
export const metadata = {
title: `Commerce Automation Recipe`,
}
# {metadata.title} <BetaBadge text="Soon" tooltipText="This recipe is a work in progress." />
# {metadata.title}
This recipe provides the general steps to implement commerce automation with Medusa.
@@ -36,11 +35,11 @@ Customer support is essential to build a store's brand and customer loyalty. Thi
You can use the Notification Module to send notifications when an action is triggered, such as when a customer or their order is updated.
{/* <Note title="Tip">
<Note title="Tip">
The [Events reference](../../events-reference/page.mdx) shows an extensive list of events triggered by the each commerce module.
The [Events reference](../../events-reference/page.mdx) shows an extensive list of events triggered for each commerce module.
</Note> */}
</Note>
Medusa also provides Notification Module Providers that integrate with third-party services, such as SendGrid.
@@ -77,211 +76,6 @@ To implement that:
icon={AcademicCapSolid}
/>
<Details summaryContent="Example: Synchronizing products with a third-party service">
For example, create the file `src/workflows/sync-products.ts` with the following content:
export const syncProductsWorkflowHighlight = [
["20", "retrieveStoreStep", "A step that retrieves the store by its ID."],
["36", "retrieveProductsToUpdateStep", "A step that retrieves the products to update based on a last update date."],
["56", "syncProductsStep", "A step to sync the product with a third-party service."],
["59", "productSyncModuleService", "Assuming this is a custom module's main service that provides connection to the third-party service."],
["63", "productsBeforeSync", "Retrieve old product data from third-party service for compensation function."],
["68", "sync", "Sync the product data in the third-party service."],
["72", "", "Pass products data before sync to compensation function."],
["75", "", "A compensation function to revert the sync when an error occurs."],
["81", "sync", "Revert the product's data in the third-party service to its old data before the synchronization."],
["90", "updateStoreLastSyncStep", "A step to update the `last_sync_data` of the store."],
["96", "prevLastSyncDate", "Retrieve the previous value of `last_sync_date` to pass it to compensation function."],
["98", "update", "Update the `last_sync_date` of the store."],
["106", "", "Pass previous last sync date to compensation function."],
["109", "", "A compensation function to revert the update of `last_sync_data` if an error occurs."],
["125", "syncProductsWorkflow", "Define the workflow that uses the above steps."]
]
```ts title="src/workflows/sync-products.ts" highlights={syncProductsWorkflowHighlight} collapsibleLines="1-16" expandButtonLabel="Show Imports"
import {
Modules,
} from "@medusajs/framework/utils"
import {
IProductModuleService,
IStoreModuleService,
ProductDTO,
StoreDTO,
} from "@medusajs/framework/types"
import {
StepResponse,
createStep,
createWorkflow,
} from "@medusajs/framework/workflows-sdk"
type RetrieveStoreStepInput = {
id: string
}
const retrieveStoreStep = createStep(
"retrieve-store-step",
async ({ id }: RetrieveStoreStepInput, { container }) => {
const storeModuleService: IStoreModuleService =
container.resolve(Modules.STORE)
const store = await storeModuleService.retrieveStore(id)
return new StepResponse({ store })
}
)
type RetrieveProductsToUpdateStepInput = {
last_sync_date?: string
}
const retrieveProductsToUpdateStep = createStep(
"retrieve-products-to-update-step",
async ({ last_sync_date }: RetrieveProductsToUpdateStepInput, { container }) => {
const productModuleService: IProductModuleService =
container.resolve(Modules.PRODUCT)
const products = await productModuleService.listProducts({
updated_at: {
$gt: last_sync_date,
},
})
return new StepResponse({ products })
}
)
type SyncProductsStepInput = {
products: ProductDTO[]
}
const syncProductsStep = createStep(
"sync-products-step",
async ({ products }: SyncProductsStepInput, { container }) => {
const productSyncModuleService = container.resolve(
"productSyncModuleService"
)
const productsBeforeSync = await productSyncModuleService.listProductSyncs({
id: products.map((product) => product.id),
})
for (const product of products) {
await productSyncModuleService.sync(product)
}
return new StepResponse({}, {
products: productsBeforeSync,
})
},
async ({ products }, { container }) => {
const productSyncModuleService = container.resolve(
"productSyncModuleService"
)
for (const product of products) {
await productSyncModuleService.sync(product)
}
}
)
type UpdateStoreLastSyncStepInput = {
store: StoreDTO
}
const updateStoreLastSyncStep = createStep(
"update-store-last-sync-step",
async ({ store }: UpdateStoreLastSyncStepInput, { container }) => {
const storeModuleService: IStoreModuleService =
container.resolve(Modules.STORE)
const prevLastSyncDate = store.metadata.last_sync_date
await storeModuleService.updateStores(store.id, {
metadata: {
last_sync_date: (new Date()).toString(),
},
})
return new StepResponse({}, {
id: store.id,
last_sync_date: prevLastSyncDate,
})
},
async ({ id, last_sync_date }, { container }) => {
const storeModuleService: IStoreModuleService =
container.resolve(Modules.STORE)
await storeModuleService.updateStores(id, {
metadata: {
last_sync_date,
},
})
}
)
type SyncProductsWorkflowInput = {
store_id: string
}
export const syncProductsWorkflow = createWorkflow(
"sync-products-workflow",
function ({ store_id }: SyncProductsWorkflowInput) {
const { store } = retrieveStoreStep({
id: store_id,
})
const { products } = retrieveProductsToUpdateStep({
last_sync_date: store.metadata.last_sync_date,
})
syncProductsStep({
products,
})
updateStoreLastSyncStep({
store,
})
}
)
```
This creates a workflow with the following steps:
1. Retrieve the store by its ID.
2. Retrieve products to update based on the last date and time the products were synced. The last sync date is retrieved from the store's `metadata` property.
3. Sync the retrieved products with a third-party service. It's assumed that the connection to the third-party service is implemented within a custom module's main service.
4. Update the last sync date of the store to the current date.
Then, create a scheduled job at `src/jobs/sync-products.ts` that executes the workflow at the specified interval:
```ts
import { MedusaContainer } from "@medusajs/framework/types"
import {
syncProductsWorkflow,
} from "../workflows/sync-products"
export default async function syncProductsJob(
container: MedusaContainer
) {
await syncProductsWorkflow(container)
.run({
input: {
name: "John",
},
})
}
export const config = {
name: "sync-products",
// execute every minute
schedule: "0 0 * * *",
numberOfExecutions: 3,
}
```
</Details>
---
## Order Management Automation
@@ -290,20 +84,7 @@ Using Medusa's architecture and commerce features, you can automate a large amou
To handle events within an order flow and automate actions, create a subscriber. For example, create a subscriber that listens to the `order.placed` event and automatically creates a fulfillment if predefined conditions are met.
<Note type="soon">
The `order.placed` event is currently not emitted.
</Note>
<Card
href="!docs!/learn/fundamentals/events-and-subscribers"
title="Create a Subscriber"
text="Learn how to create a subscriber in Medusa."
icon={AcademicCapSolid}
/>
{/* <CardList items={[
<CardList items={[
{
href: "!docs!/learn/fundamentals/events-and-subscribers",
title: "Create a Subscriber",
@@ -316,7 +97,7 @@ The `order.placed` event is currently not emitted.
text: "Check out triggered events by each commerce module.",
icon: AcademicCapSolid,
},
]} /> */}
]} />
---
@@ -361,12 +142,6 @@ For example, to group customers with over twenty orders:
1. Create a subscriber that listens to the `order.placed` event.
2. If the customer has more than 20 orders, add them to the VIP customer group.
<Note type="soon">
The `order.placed` event is currently not emitted.
</Note>
<CardList items={[
{
href: "/commerce-modules/customer",
@@ -386,91 +161,14 @@ The `order.placed` event is currently not emitted.
text: "Learn how to create a subscriber in Medusa.",
icon: AcademicCapSolid,
},
{
href: "/events-reference",
title: "Events Reference",
text: "Check out triggered events by each commerce module.",
icon: AcademicCapSolid,
},
]} />
<Details summaryContent="Example: Add customer to VIP group">
Here’s an example of a subscriber that listens to the `order.placed` event and checks whether the customer should be added to the VIP customer group based on their number of orders:
<Note type="soon">
The `order.placed` event is currently not emitted.
</Note>
```ts title="src/subscribers/add-custom-to-vip.ts" collapsibleLines="1-12" expandButtonLabel="Show Imports"
import type {
SubscriberArgs,
SubscriberConfig,
} from "@medusajs/framework"
import {
Modules,
} from "@medusajs/framework/utils"
import {
ICustomerModuleService,
IOrderModuleService,
} from "@medusajs/framework/types"
export default async function orderCreatedHandler({
event: { data },
container,
}: SubscriberArgs<{ id: string }>) {
const orderId = data.id
const orderModuleService: IOrderModuleService = container
.resolve(Modules.ORDER)
const customerModuleService:
ICustomerModuleService = container.resolve(
Modules.CUSTOMER
)
// check if VIP group exists
const vipGroup = await customerModuleService
.listCustomerGroups({
name: "VIP",
}, {
relations: ["customers"],
})
if (!vipGroup.length) {
return
}
// retrieve the order
const order = await orderModuleService.retrieveOrder(orderId)
if (!order ||
!order.customer_id ||
vipGroup[0].customers.find(
(customer) => customer.id === order.customer_id
) !== undefined) {
return
}
const [, count] = await orderModuleService.listAndCountOrders({
customer_id: order.customer_id,
})
if (count < 20) {
return
}
// add customer to VIP group
await customerModuleService.addCustomerToGroup({
customer_group_id: vipGroup[0].id,
customer_id: order.customer_id,
})
}
export const config: SubscriberConfig = {
event: "order.placed",
}
```
</Details>
---
## Marketing Automation
@@ -495,99 +193,3 @@ You can also create a scheduled job that checks whether the number of new produc
icon: AcademicCapSolid,
},
]} />
<Details summaryContent="Example: Sending a newsletter email after adding ten products">
For example, create the file `src/subscribers/send-products-newsletter.ts` with the following content:
export const newsletterHighlights = [
["32", "store", "Retrieve the first store in the application."],
["34", "products", "Retrieve the products created since the last newsletter send date."],
["40", "", "Check whether more than 10 products have been created before proceeding."],
["44", "customers", "Retrieve all customers, assuming they're considered subscribed."],
["46", "createNotifications", "Send a notification (newsletter) to each customer using the Notification Module."],
["49", '"email"', "Send the notification through the email channel."],
["50", '"newsletter_template"', "Specify the template name in the third-party service (for example, SendGrid)."],
["52", "products", "Pass the created products to the template."],
["57", "updateStores", "Update the store's `last_newsletter_send_date` property with the current date."]
]
```ts title="src/subscribers/send-products-newsletter.ts" highlights={newsletterHighlights} collapsibleLines="1-14" expandButtonLabel="Show Imports"
import type {
SubscriberArgs,
SubscriberConfig,
} from "@medusajs/framework"
import {
Modules,
} from "@medusajs/framework/utils"
import {
ICustomerModuleService,
IProductModuleService,
IStoreModuleService,
INotificationModuleService,
} from "@medusajs/framework/types"
export default async function productCreateHandler({
container,
}: SubscriberArgs<{ id: string }>) {
const productModuleService: IProductModuleService =
container.resolve(Modules.PRODUCT)
const storeModuleService: IStoreModuleService =
container.resolve(Modules.STORE)
const customerModuleService: ICustomerModuleService =
container.resolve(Modules.CUSTOMER)
const notificationModuleService:
INotificationModuleService = container.resolve(
Modules.NOTIFICATION
)
const store = (await storeModuleService.listStores())[0]
const products = await productModuleService.listProducts({
created_at: {
$gt: store.metadata.last_newsletter_send_date,
},
})
if (products.length < 10) {
return
}
const customers = await customerModuleService.listCustomers()
await notificationModuleService.createNotifications(
customers.map((customer) => ({
to: customer.email,
channel: "email",
template: "newsletter_template",
data: {
products,
},
}))
)
await storeModuleService.updateStores(store.id, {
metadata: {
last_newsletter_send_date: (new Date()).toString(),
},
})
}
export const config: SubscriberConfig = {
event: "product.created",
}
```
In the subscriber function, you:
1. Retrieve the first store in our application.
2. Retrieve products created since the last time a newsletter is sent. The last send date is stored in the store's `metadata` property.
3. If the count of last created products is less than 10, stop execution.
4. Retrieve all customers. Here, it's assumed that all customers are considered subscribed for simplicity.
5. Use the Notification Module to send a notification to the customer. This uses the Notification Module Provider configured for the `email` channel.
6. Update the store's `last_newsletter_send_date` with the current date.
</Details>
@@ -1,5 +1,4 @@
import { AcademicCapSolid, BoltSolid, PuzzleSolid } from "@medusajs/icons"
import { LearningPath } from "docs-ui"
export const metadata = {
title: `Digital Products Recipe`,
@@ -70,8 +69,8 @@ Then, you can link your custom data model to data models from other modules. For
},
{
href: "!docs!/learn/fundamentals/module-links",
title: "Module Links",
text: "Learn how to link data models of different modules.",
title: "Define Module Links",
text: "Define links between data models.",
icon: AcademicCapSolid,
},
]} />
@@ -173,12 +172,6 @@ When a customer purchases a digital product, they should receive a link to downl
You can create or install a fulfillment module provider that handles the logic of fulfilling the digital product.
<Note type="soon">
Fulfillment providers are under development.
</Note>
<Card
href="/commerce-modules/fulfillment"
title="Fulfillment Module"
@@ -1,5 +1,4 @@
import { AcademicCapSolid, UsersSolid, PuzzleSolid } from "@medusajs/icons"
import { LearningPath } from "docs-ui"
export const metadata = {
title: `Ecommerce Recipe`,
@@ -1,5 +1,4 @@
import { AcademicCapSolid, UsersSolid } from "@medusajs/icons"
import { LearningPath } from "docs-ui"
export const metadata = {
title: `Multi-Region Store Recipe`,
@@ -27,89 +26,77 @@ Merchants specify the currency of each region. Multiple regions can have the sam
When customers view your products from a region, they see the prices in the region’s currency.
### Tax rates and providers
### Tax Regions and Rates
Merchants define a default tax rate and tax rates for specific conditions (for example, for a particular set of products) in a region. Each region also has a different tax provider that calculates the taxes. You can use Medusa's default tax provider or create a custom tax provider.
Merchants can define tax regions, which are tax-related settings for a specific country. For each tax region, merchants can set a default tax rate and override it with tax rates for specific conditions, such as product types.
During checkout, the taxes are calculated based on the customer's region, tax configurations, and rates.
During checkout, Medusa calculates the taxes using the tax region settings of the customer's region and selected country in their shipping address.
<CardList items={[
{
href: "#",
title: "Manage Taxes in Medusa Admin",
text: "Manage taxes in Medusa Admin.",
href: "!user-guides!/settings/tax-regions",
title: "Using Medusa Admin",
text: "Learn how to manage tax regions in the Medusa Admin",
icon: UsersSolid,
badge: {
variant: "blue",
children: "Guide Soon"
}
},
{
href: "!api!/admin#tax-regions_posttaxregions",
title: "Manage Taxes Using Admin APIs",
text: "Manage tax settings using the Admin APIs.",
title: "Using Admin APIs",
text: "Manage tax regions using the Admin APIs.",
icon: AcademicCapSolid,
},
]} />
<Card
href="/references/tax/provider"
title="Create Tax Provider"
text="Learn how to create a tax provider."
icon={AcademicCapSolid}
className="mt-1"
/>
### Payment and Fulfillment Providers
Merchants choose which payment and fulfillment providers are available in each region. For example, one region can use Payment Provider A and B while another only uses Payment Provider B.
Merchants choose which payment providers are available in each region. For example, one region can use Payment Provider A and B while another only uses Payment Provider B. Merchants can also choose the fulfillment providers available in each stock location, and provide shipping options using the providers in those locations.
During checkout, customers only see the payment providers and shipping options configured for the region. This lets you give customers a localized experience that feels familiar and instills trust.
During checkout, customers only see the payment providers configured for the region, and they can only choose shipping options that can be used to fulfill items to their shipping address. This allows merchants to give customers a localized experience that feels familiar and instills trust.
Medusa provides official module providers for payment and fulfillment. You can also create custom module providers.
<CardList items={[
{
href: "#",
title: "Manage Providers in Medusa Admin",
text: "Learn how to manage providers in Medusa Admin.",
href: "!user-guide!/settings/regions",
title: "Manage Payment Providers in Medusa Admin",
text: "Learn how to manage providers in a region.",
icon: UsersSolid,
badge: {
variant: "blue",
children: "Guide Soon"
}
},
{
href: "/integrations",
title: "Integrations",
text: "Check out available integrations, including payment module providers.",
icon: AcademicCapSolid,
href: "!user-guide!/settings/locations-and-shipping/locations#manage-fulfillment-providers",
title: "Manage Fulfillment Providers in Medusa Admin",
text: "Learn how to manage providers in a location.",
icon: UsersSolid,
},
]} />
<Card
href="/integrations"
title="Integrations"
text="Check out available integrations, including payment module providers."
icon={AcademicCapSolid}
className="mt-1"
/>
---
## Prices Per Region and Currency
Merchants sets the price of a product price per currency and region. This also applies to adding sales or overriding prices for specific conditions using the Pricing Module's features.
Merchants set the price of a product's variants per currency and region. This also applies to adding sales or overriding prices for specific conditions.
Using the tax-inclusive feature, merchants can specify prices including taxes per currency and region. Medusa then calculates the tax amount applied to a line item in the cart based on the region's tax configurations.
Using the tax-inclusive feature, merchants can also specify prices including taxes per currency and region. Medusa then calculates the tax amount applied to a line item in the cart based on the region's tax configurations.
<CardList items={[
{
href: "#",
title: "Setting Product Prices in Medusa Admin",
text: "Learn how to set a product prices in Medusa Admin.",
href: "!user-guide!/products/variants#edit-product-variant-prices",
title: "Setting Variant Prices in Medusa Admin",
text: "Learn how to set a variant's prices in Medusa Admin.",
icon: UsersSolid,
badge: {
variant: "blue",
children: "Guide Soon"
}
},
{
href: "/storefront-development/products/price",
title: "Display Product Price in Storefront",
title: "Display Variant Price in Storefront",
text: "Learn how to display the correct product price in a storefront.",
icon: AcademicCapSolid,
},
@@ -119,32 +106,22 @@ Using the tax-inclusive feature, merchants can specify prices including taxes pe
## Multi-Warehouse Support
Medusa's Inventory and Stock Location Modules provide multi-warehouse features that allow merchants to manage inventory across different locations. Merchants then control which location an item in an order is fulfilled, allowing them to keep a correct inventory count across locations and sales channels.
Medusa's [Inventory](../../commerce-modules/inventory/page.mdx) and [Stock Location](../../commerce-modules/stock-location/page.mdx) Modules provide multi-warehouse features that allow merchants to manage inventory across different locations. Merchants then control which location an item in an order is fulfilled from, allowing them to keep a correct inventory count across locations and sales channels.
A multi-regional setup lets merchants manage their inventory through Medusa across the different regions they serve. Customers are always shown accurate inventory information based on the location associated with their sales channel.
{/* TODO add links */}
<CardList items={[
{
href: "#",
href: "!user-guide!/settings/locations-and-shipping/locations",
title: "Manage Stock Locations",
text: "Learn how to manage stock locations in the Medusa Admin.",
icon: UsersSolid,
badge: {
variant: "blue",
children: "Guide Soon"
}
},
{
href: "#",
href: "!user-guide!/inventory",
title: "Manage Inventory",
text: "Learn how to manage inventory in the Medusa Admin.",
icon: UsersSolid,
badge: {
variant: "blue",
children: "Guide Soon"
}
},
]} />
@@ -154,11 +131,19 @@ A multi-regional setup lets merchants manage their inventory through Medusa acro
By integrating a third-party Content Management Systems (CMS), you benefit from rich content features including managing your content in multiple languages. This allows you to cater to customers’ different languages in the regions you serve.
To integrate a third-party system, create a custom module whose main service connects to that third-party service.
To integrate a third-party system, create a custom module whose main service connects to that third-party service. You can also follow the [Sanity integration guide](../../integrations/guides/sanity/page.mdx) to integrate Sanity with Medusa.
<Card
href="!docs!/learn/fundamentals/modules"
title="Create a Module"
text="Learn how to create a module in Medusa."
icon={AcademicCapSolid}
/>
<CardList items={[
{
href: "!docs!/learn/fundamentals/modules",
title: "Create a Module",
text: "Learn how to create a module in Medusa.",
icon: AcademicCapSolid,
},
{
href: "/integrations/guides/sanity",
title: "Integrate Sanity",
text: "Follow a step-by-step guide to integrate Sanity.",
icon: AcademicCapSolid,
},
]} />
@@ -1,5 +1,4 @@
import { AcademicCapSolid, BoltSolid } from "@medusajs/icons"
import { LearningPath } from "docs-ui"
export const metadata = {
title: `Omnichannel Commerce Recipe`,
@@ -15,7 +14,7 @@ Merchants selling across different channels need an efficient way to manage thei
Omnichannel commerce also provides customers a seamless shopping experience, regardless of where they’re shopping. Whether they’re buying your products from your online store, a marketplace like Amazon, or through social media, you provide them with a good experience and handle orders consistently.
Medusa’s modular architecture facilitates building omnichannel commerce, as your server and storefront aren’t tightly coupled. You can also use the Sales Channel Module's features to expand your business into other avenues like marketplaces and social commerce.
Medusa’s modular architecture facilitates building omnichannel commerce, as your server and storefront aren’t tightly coupled. You can also use the [Sales Channel Module](../../commerce-modules/sales-channel/page.mdx)'s features to expand your business into other avenues like marketplaces and social commerce.
---
+46 -44
View File
@@ -48,14 +48,16 @@ For example, you can support importing orders into Medusa through a custom API R
text: "Learn how to create a custom API Route.",
icon: AcademicCapSolid,
},
{
href: "!docs!/learn/fundamentals/scheduled-jobs",
title: "Create Scheduled Jobs",
text: "Learn how to create a scheduled job.",
icon: AcademicCapSolid,
}
]} />
<Card
href="!docs!/learn/fundamentals/scheduled-jobs"
title="Create Scheduled Jobs"
text="Learn how to create a scheduled job."
icon={AcademicCapSolid}
className="mt-1"
/>
---
## Route Orders to Third-party Fulfillment Services
@@ -68,12 +70,6 @@ Medusa uses the Fulfillment Module whenever a fulfillment action is performed, s
In addition, create a subscriber that listen to fulfillment-related events, such as the `order.fulfillment_created` event, to perform actions with the third-party fulfillment provider.
<Note type="soon">
Emitting of event `order.fulfillment_created` isn't implemented yet.
</Note>
<CardList itemsPerRow={2} items={[
{
href: "/references/fulfillment/provider",
@@ -82,26 +78,28 @@ Emitting of event `order.fulfillment_created` isn't implemented yet.
icon: AcademicCapSolid,
},
{
href: "!docs!/learn/fundamentals/events-and-subscribers",
title: "Create a Subscriber",
text: "Learn about create a subscriber",
href: "/commerce-modules/order/events",
title: "Order Events",
text: "Learn about the events emitted related to the Order Module",
icon: AcademicCapSolid,
}
},
]} />
<Card
href="!docs!/learn/fundamentals/events-and-subscribers"
title="Create a Subscriber"
text="Learn about create a subscriber"
icon={AcademicCapSolid}
className="mt-1"
/>
---
## Process Payment with Third-Party Providers
To integrate third-party payment providers with the Medusa application, create a payment module provider.
In addition, create a subscriber that listen to payment-related events, such as the `order.payment_captured` event, to perform actions in the third-party payment provider.
<Note type="soon">
Emitting of event `order.payment_captured` isn't implemented yet.
</Note>
In addition, create a subscriber that listen to payment-related events, such as the `payment.captured` event, to perform actions in the third-party payment provider.
<CardList itemsPerRow={2} items={[
{
@@ -111,13 +109,21 @@ Emitting of event `order.payment_captured` isn't implemented yet.
icon: AcademicCapSolid,
},
{
href: "!docs!/learn/fundamentals/events-and-subscribers",
title: "Create a Subscriber",
text: "Learn about create a subscriber",
href: "/commerce-modules/payment/events",
title: "Payment Events",
text: "Learn about the events emitted related to the Payment Module",
icon: AcademicCapSolid,
}
},
]} />
<Card
href="!docs!/learn/fundamentals/events-and-subscribers"
title="Create a Subscriber"
text="Learn about create a subscriber"
icon={AcademicCapSolid}
className="mt-1"
/>
---
## Track Inventory Across Sales Channels
@@ -153,24 +159,12 @@ When an order is placed, the item's quantity is reserved from the stock location
## Handle Returns, Exchanges, and Changes
<Note type="soon">
All types of order changes are coming soon.
</Note>
In Medusa, items in an order can be returned or exchanged; these can be created by the merchant or requested by the customer. A merchant can also edit an order to add, update, or delete items.
In Medusa, items in an order can be returned or exchanged. A merchant can also edit an order to add, update, or delete items.
When changes are made to an order by any of the mentioned actions, the changes are reflected on the order's totals and associated inventory. The integrated fulfillment and payment module providers are used if fulfillment or payment actions are required, such as fulfilling exchanged items.
Medusa also emits events related to these actions, such as `order.return_requested`. So, you can create a subscriber that listens to these events and perform asynchronous actions, such as communicating with third-party services.
<Note type="soon">
Emitting of event `order.return_requested` isn't implemented yet.
</Note>
<CardList items={[
{
href: "/commerce-modules/order/order-change",
@@ -179,9 +173,17 @@ Emitting of event `order.return_requested` isn't implemented yet.
icon: AcademicCapSolid,
},
{
href: "!docs!/learn/fundamentals/events-and-subscribers",
title: "Create a Subscriber",
text: "Learn about create a subscriber",
href: "/commerce-modules/order/events",
title: "Order Events",
text: "Learn about the events emitted related to the Order Module",
icon: AcademicCapSolid,
}
},
]} />
<Card
href="!docs!/learn/fundamentals/events-and-subscribers"
title="Create a Subscriber"
text="Learn about create a subscriber"
icon={AcademicCapSolid}
className="mt-1"
/>
@@ -1,5 +1,4 @@
import { AcademicCapSolid, NextJs } from "@medusajs/icons"
import { LearningPath } from "docs-ui"
export const metadata = {
title: `Personalized Products Recipe`,
@@ -44,7 +43,7 @@ Two line items in the cart having different `metadata` attributes are not consid
</Note>
In more complex cases, you can create a custom module that stores and manages the personalization data models. You can also create a relationship between these data models and the `LineItem` data model.
In more complex cases, you can create a custom module that stores and manages the personalization data models. You can also create a link between these data models and the `LineItem` data model.
<CardList items={[
{
@@ -54,18 +53,18 @@ In more complex cases, you can create a custom module that stores and manages th
icon: AcademicCapSolid,
},
{
href: "!docs!/learn/fundamentals/modules#1-create-data-model",
title: "Create a Data Model",
text: "Learn how to create a data model.",
href: "!docs!/learn/fundamentals/module-links",
title: "Define Module Link",
text: "Define link between data models.",
icon: AcademicCapSolid,
}
},
]} />
---
## Build a Custom Storefront
Due to Medusa's modular architecture, there are no restrictions on the framework you use to build the storefront, or design and experience you provide customers. The storefront connects to the Medusa application using the Store API Routes.
Medusa's modular architecture removes any restrictions on the framework you use to build the storefront, or design and experience you provide customers. The storefront connects to the Medusa application using the Store API Routes.
You can build a unique experience around your products that focuses on the customer’s personalization capabilities.
@@ -121,7 +120,7 @@ The Fulfillment Module registers your fulfillment module provider to use it to f
<Card
href="/references/fulfillment/provider"
title="Create a Fulfillment Service"
title="Create a Fulfillment Provider"
text="Learn how to create a fulfillment provider in Medusa."
icon={AcademicCapSolid}
/>
+19 -53
View File
@@ -1,5 +1,4 @@
import { AcademicCapSolid } from "@medusajs/icons"
import { LearningPath } from "docs-ui"
export const metadata = {
title: `Point-of-Sale (POS) Recipe`,
@@ -68,50 +67,13 @@ To search through product variants by their barcode, create a custom API Route a
]}
/>
<Details summaryContent="Example: Search Products By Barcode API Route">
Here’s an example of creating a custom API Route at `/store/pos/search-barcode` that searches product variants by a barcode:
```ts title="src/api/store/pos/search-barcode/route.ts" collapsibleLines="1-8" expandButtonLabel="Show Imports"
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
import { MedusaError } from "@medusajs/framework/utils"
import { Modules } from "@medusajs/framework/utils"
import { IProductModuleService } from "@medusajs/framework/types"
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
const barcode = (req.query.barcode as string) || ""
if (!barcode) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, "Barcode is required")
}
// get product service
const productModuleService: IProductModuleService = req.scope.resolve(
Modules.PRODUCT
)
// retrieve product variants by barcode
const productVariants = await productModuleService.listProductVariants({
// @ts-ignore
barcode,
})
res.json({
product_variants: productVariants,
})
}
```
</Details>
---
## Access Accurate Inventory Details
As you manage an online and offline store, it's essential to separate inventory quantity across different locations.
Medusa's Inventory, Stock Location, and Sales Channel modules allow merchants to manage the inventory items and their availability across locations and sales channels.
Medusa's [Inventory](../../commerce-modules/inventory/page.mdx), [Stock Location](../../commerce-modules/stock-location/page.mdx), and [Sales Channel](../../commerce-modules/sales-channel/page.mdx) modules allow merchants to manage the inventory items and their availability across locations and sales channels.
![Using Multi-warehouse features with POS](https://res.cloudinary.com/dza7lstvk/image/upload/v1709034731/Medusa%20Book/pos-multiwarehouse_r1z48x.jpg)
@@ -133,22 +95,24 @@ This also opens the door for other business opportunities, such as an endless ai
text: "Learn about the Stock Location Module.",
icon: AcademicCapSolid,
},
{
href: "/commerce-modules/sales-channel",
title: "Sales Channel Module",
text: "Learn about the Sales Channel Module.",
icon: AcademicCapSolid,
},
]}
/>
<Card
href="/commerce-modules/sales-channel"
title="Sales Channel Module"
text="Learn about the Sales Channel Module."
icon={AcademicCapSolid}
className="mt-1"
/>
---
## Build an Omni-channel Customer Experience
Using Medusa's Customer Module, you can retrieve a customer's details from the Medusa application and place an order on the POS under their account. The customer can then view their order details on their online profile as if they had placed the order online.
Using Medusa's [Customer Module](../../commerce-modules/customer/page.mdx), you can retrieve a customer's details from the Medusa application and place an order on the POS under their account. The customer can then view their order details on their online profile as if they had placed the order online.
In addition, using Medusa's Promotion Module, store operators can create promotions on the fly for customers using the POS system and apply them to their orders.
In addition, using Medusa's [Promotion Module](../../commerce-modules/promotion/page.mdx), store operators can create promotions on the fly for customers using the POS system and apply them to their orders.
You can also create custom modules to provide features for a better customer experience, such as a rewards system or loyalty points.
@@ -166,15 +130,17 @@ You can also create custom modules to provide features for a better customer exp
text: "Learn about the Promotion Module.",
icon: AcademicCapSolid,
},
{
href: "!docs!/learn/fundamentals/modules",
title: "Create a Module",
text: "Learn how to create a module.",
icon: AcademicCapSolid,
},
]}
/>
<Card
href="!docs!/learn/fundamentals/modules"
title="Create a Module"
text="Learn how to create a module."
icon={AcademicCapSolid}
className="mt-1"
/>
---
## Accept Payment, Place Order, and Use RMA Features
@@ -1,5 +1,4 @@
import { AcademicCapSolid, Github } from "@medusajs/icons"
import { LearningPath } from "docs-ui"
export const metadata = {
title: `Subscriptions Recipe`,
@@ -77,7 +76,7 @@ Implementing the logic depends on your use case, but you'll mainly implement the
1. Create an API route in place of the [Complete Cart Store API Route](!api!/store#carts_postcartsidcomplete) that creates a subscription for the order.
2. Create a scheduled job that checks daily for subscriptions that need renewal.
3. Create a scheduled job that checks daily for subscriptions that are expired.
3. Create another scheduled job that checks daily for subscriptions that are expired.
<CardList itemsPerRow={2} items={[
{