docs: added new recipes (#4964)

* docs: added new recipes

* added oms recipe

* address PR feedback
This commit is contained in:
Shahed Nasser
2023-09-11 11:31:57 +03:00
committed by GitHub
parent 5c9f8c7111
commit d971d5cf91
12 changed files with 2891 additions and 69 deletions

View File

@@ -0,0 +1,177 @@
---
addHowToData: true
---
# Restock Notifications Plugin
In this document, youll learn how to install the restock notification plugin on your Medusa backend.
:::note
This plugin doesn't actually implement the sending of the notification, only the required implementation to trigger restock events and allow customers to subscribe to product variants' stock status. To send the notification, you need to use a [notification plugin](../notifications/).
:::
## Overview
Customers browsing your products may find something that they need, but it's unfortunately out of stock. In this scenario, you can keep them interested in your product and, subsequently, in your store by notifying them when the product is back in stock.
The Restock Notifications plugin provides new endpoints that allow the customer to subscribe to restock notifications of a specific product variant. It also triggers the `restock-notification.restocked` event whenever a product variant's stock quantity is above a specified threshold. The event's payload includes the ID of the product variant and the customer emails subscribed to it. You can pair this with a subscriber that listens to that event and sends a notification to the customer using a [Notification plugin](../notifications/).
---
## Prerequisites
### Medusa Backend
Before you follow this guide, you must have a Medusa backend installed. If not, you can follow the [quickstart guide](../../create-medusa-app.mdx) to learn how to do it.
### Event-Bus Module
To trigger events to the subscribed handler methods, you must have an event-bus module installed. For development purposes, you can use the [Local module](../../development/events/modules/local.md) which should be enabled by default in your Medusa backend.
For production, it's recommended to use the [Redis module](../../development/events/modules/redis.md).
---
## Install Plugin
In the root directory of your Medusa backend, run the following command to install the Restock Notifications plugin:
```bash npm2yarn
npm install medusa-plugin-restock-notification
```
Then, add the plugin into the plugins array exported as part of the Medusa configuration in `medusa-config.js`:
```js title=medusa-config.js
const plugins = [
// other plugins...
{
resolve: `medusa-plugin-restock-notification`,
options: {
// optional options
trigger_delay, // delay time in milliseconds
inventory_required, // minimum restock inventory quantity
},
},
]
```
The plugin accepts the following optional options:
1. `trigger_delay`: a number indicating the time in milliseconds to delay the triggering of the `restock-notification.restocked` event. Default value is `0`.
2. `inventory_required`: a number indicating the minimum inventory quantity to consider a product variant as restocked. Default value is `0`.
Finally, run the migrations of this plugin before you start the Medusa backend:
```bash
npx medusa migrations run
```
---
## Test Plugin
### 1. Run Medusa Backend
In the root of your Medusa backend project, run the following command to start the Medusa backend:
```bash npm2yarn
npm run start
```
### 2. Subscribe to Variant Restock Notifications
Then, send a `POST` request to the endpoint `<BACKEND_URL>/restock-notifications/variants/<VARIANT_ID>` to subscribe to restock notifications of a product variant ID. Note that `<BACKEND_URL>` refers to the URL fo your Medusa backend, which is `http://localhost:9000` during development, and `<VARIANT_ID>` refers to the ID of the product variant you're subscribing to.
:::note
You can only subscribe to product variants that are out-of-stock. Otherwise, you'll receive an error.
:::
The endpoint accepts the following request body parameters:
1. `email`: a string indicating the email that is subscribing to the product variant's restock notification.
2. `sales_channel_id`: an optional string indicating the ID of the sales channel to check the stock quantity in when subscribing. This is useful if you're using multi-warehouse modules, as the product variant's quantity is checked correctly when checking if it's out of stock. Alternatively, you can pass the [publishable API key in the header of the request](../../development/publishable-api-keys/storefront/use-in-requests.md) and the sales channel will be derived from it.
### 3. Trigger Restock Notification
After subscribing to the out-of-stock variant, change its stock quantity to the minimum inventory required to test out the event trigger. The new stock quantity should be any value above `0` if you didn't set the `inventory_required` option.
You can use the [Medusa admin](../../user-guide/products/manage.mdx#manage-product-variants) or the [Admin REST API endpoints](https://docs.medusajs.com/api/admin#products_postproductsproductvariantsvariant) to update the quantity.
After you update the quantity, you can see the `restock-notification.restocked` triggered and logged in the Medusa backend logs. If you've implemented the notification sending, this is where it'll be triggered and a notification will be sent.
---
## Example: Implement Notification Sending with SendGrid
:::note
The SendGrid plugin already listens to and handles the `restock-notification.restocked` event. So, if you install it you don't need to manually create a subscriber that handles this event as explained here. This example is only provided for reference on how you can send a notification to the customer using a Notication plugin.
:::
Here's an example of a subscriber that listens to the `restock-notification.restocked` event and uses the [SendGrid plugin](../notifications/sendgrid.mdx) to send the subscribed customers an email:
```ts title=src/subscribers/restock-notification.ts
import {
EventBusService,
ProductVariantService,
} from "@medusajs/medusa"
type InjectedDependencies = {
eventBusService: EventBusService,
sendgridService: any
productVariantService: ProductVariantService
}
class RestockNotificationSubscriber {
protected sendGridService_: any
protected productVariantService_: ProductVariantService
constructor({
eventBusService,
sendgridService,
productVariantService,
}: InjectedDependencies) {
this.sendGridService_ = sendgridService
this.productVariantService_ = productVariantService
eventBusService.subscribe(
"restock-notification.restocked",
this.handleRestockNotification
)
}
handleRestockNotification = async ({
variant_id,
emails,
}) => {
// retrieve variant
const variant = await this.productVariantService_.retrieve(
variant_id
)
this.sendGridService_.sendEmail({
templateId: "restock-notification",
from: "hello@medusajs.com",
to: emails,
data: {
// any data necessary for your template...
variant,
},
})
}
}
export default RestockNotificationSubscriber
```
Handler methods subscribed to the `restock-notification.restocked` event, which in this case is the `handleRestockNotification` method, receive the following object data payload as a parameter:
- `variant_id`: The ID of the variant that has been restocked.
- `emails`: An array of strings indicating the email addresses subscribed to the restocked variant. Here, you pass it along to the SendGrid plugin directly to send the email to everyone subscribed. If necessary, you can also retrieve the customer of that email using the `CustomerService`'s [retrieveByEmail](../../references/services/classes/CustomerService.md#retrievebyemail) method.
In the method, you retrieve the variant by its ID using the `ProductVariantService`, then send the email using the SendGrid plugins' `SendGridService`.

View File

@@ -0,0 +1,689 @@
---
addHowToData: true
---
import DocCardList from '@theme/DocCardList';
import DocCard from '@theme/DocCard';
import Icons from '@theme/Icon';
# Commerce automation
This document guides you on how you can implement different forms of commerce automation within your Medusa project.
## Overview
Commerce automation is essential for businesses that want to save costs, provide better user experience, and avoid manual, repetitive tasks that can lead to human errors. Businesses can utilize it in different domains, including marketing, customer support, order management, and more.
Medusa provides you with the necessary architecture and resources to implement commerce automation related to order management, customer service, and more. Mainly, it utilizes an event bus that allows you to listen to certain event triggers and perform asynchronously actions.
This document gives a high-level overview of how you can implement different types of commerce automation.
---
## Re-Stock Notifications
Customers may be interested in a product that is currently out of stock.
Medusa already provides a [Re-stock notifications plugin](../plugins/other/restock-notifications.md). You can also implement this by creating custom entities, triggering custom events, and handling these events with a subscriber.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/plugins/other/restock-notifications',
label: 'Restock Notifications Plugin',
customProps: {
icon: Icons['bolt-solid'],
description: 'Learn how to install the Restock Notification plugin.',
}
},
{
type: 'link',
href: '/development/entities/create',
label: 'Create an Entity',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a custom entity in the Medusa backend.',
}
},
{
type: 'link',
href: '/development/events/#emitting-events',
label: 'Emit Events',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to emit a custom event in the Medusa backend.',
}
},
{
type: 'link',
href: '/development/events/create-subscriber',
label: 'Create a Subscriber',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a subscriber that handles events.',
}
},
]} />
---
## Automated Customer Support
Customer support is essential to build a stores brand and customer loyalty. This can include integrating with third-party services or automating notifications sent to customers when changes happen related to their orders, returns, exchanges, and more.
Using Medusas Notification Service, you can handle notifications triggered from actions on the customers orders or profile.
For example, when an order's status is updated, the `order.updated` event is triggered. You can create a Notification Service that handles this event by sending the customer an email informing them of the status update.
The [Event reference](../development/events/events-list.md) includes an extensive list of events triggered by the Medusa core.
Medusa also provides official notification plugins that integrate with third-party services, such as [SendGrid](../plugins/notifications/sendgrid.mdx) or [TwilioSMS](../plugins/notifications/twilio-sms.md).
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/plugins/notifications',
label: 'Notification Plugins',
customProps: {
icon: Icons['bolt-solid'],
description: 'Check out available notification plugins.',
}
},
{
type: 'link',
href: '/development/notification/create-notification-provider',
label: 'Create Notification Service',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a notification service.',
}
},
]} />
<details>
<summary>
Example: Sending an email for new notes
</summary>
Heres an example of a subscriber that uses the SendGrid plugin to send an email to the customer when the order has a new note:
```ts title=src/subscribers/new-note.ts
import {
EventBusService,
NoteService,
OrderService,
} from "@medusajs/medusa"
type InjectedDependencies = {
eventBusService: EventBusService
sendgridService: any
noteService: NoteService
orderService: OrderService
}
class NewNoteSubscriber {
protected sendGridService_: any
protected noteService_: NoteService
protected orderService_: OrderService
constructor({
eventBusService,
sendgridService,
noteService,
orderService,
}: InjectedDependencies) {
this.noteService_ = noteService
this.orderService_ = orderService
this.sendGridService_ = sendgridService
eventBusService.subscribe(
"note.created",
this.handleNoteCreated
)
}
handleNoteCreated = async (data) => {
// retrieve note by id
const note = await this.noteService_.retrieve(data.id, {
relations: ["author"],
})
if (!note || note.resource_type !== "order") {
return
}
// retrieve note's order
const order = await this.orderService_.retrieve(
note.resource_id
)
if (!order) {
return
}
this.sendGridService_.sendEmail({
templateId: "order-update",
from: "hello@medusajs.com",
to: order.email,
data: {
// any data necessary for your template...
note_text: note.value,
note_author: note.author.first_name,
note_date: note.created_at,
order_id: order.display_id,
},
})
}
}
export default NewNoteSubscriber
```
</details>
---
## Automatic Data Synchronization
As your commerce store gets bigger, youll likely need to synchronize data across different systems. For example, synchronizing data with an ERP system or a data warehouse.
You can implement automatic synchronization in Medusa using scheduled jobs. A scheduled job runs at a specified date and time interval in the background of your Medusa backend. Within the scheduled job, you can synchronize your internal or external data.
<DocCard item={{
type: 'link',
href: '/development/scheduled-jobs/create',
label: 'Create a Scheduled Job',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a scheduled job in Medusa.',
}
}} />
<details>
<summary>
Example: Synchronizing products with a third-party service
</summary>
Heres an example of synchronizing products with a third party service using a [loader](../development/loaders/create.md):
```ts title=src/loaders/sync-products.ts
import {
Logger,
ProductService,
StoreService,
} from "@medusajs/medusa"
import {
ProductSelector,
} from "@medusajs/medusa/dist/types/product"
import { AwilixContainer } from "awilix"
export default async (
container: AwilixContainer,
config: Record<string, unknown>
): Promise<void> => {
const logger = container.resolve<Logger>("logger")
logger.info("Synchronizing products...")
const productService = container.resolve<ProductService>(
"productService"
)
const storeService = container.resolve<StoreService>(
"storeService"
)
// retrieve store to get last sync date
const store = await storeService.retrieve()
const productFilters: ProductSelector = {}
if (store.metadata.last_sync_date) {
productFilters.updated_at = {
gt: new Date(
store.metadata.last_sync_date as string
),
}
}
const updatedProducts = await productService.list(
productFilters
)
updatedProducts.forEach((product) => {
// assuming client is an initialized connection
// with a third-party service
client.sync(product)
})
await storeService.update({
metadata: {
last_sync_date: new Date(),
},
})
logger.info("Finish synchronizing products")
}
```
Notice that here its assumed that:
1. The last update date is stored in the `Store`'s metadata object. You can instead use a custom entity to handle this.
2. The connection to the third-party service is assumed to be available and handled within the `client` variable.
</details>
---
## Order Management Automation
Using Medusas architecture and commerce features, you can automate a large amount of order management functionalities.
By utilizing the event bus service, you can handle events within an order workflow to automate actions. For example, when an order is placed, you can listen to the `order.placed` event and automatically create a fulfillment if a set of predefined conditions are met.
Another example is automatically capturing payment when an order is fully shipped and the `order.shipment_created` is triggered.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/development/events',
label: 'Event Bus',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the event architecture system in the Medusa backend.',
}
},
{
type: 'link',
href: '/development/events/create-subscriber',
label: 'Create a Subscriber',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a subscriber to listen to events.',
}
},
{
type: 'link',
href: '/development/events/events-list',
label: 'Events Reference',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Check out triggered events in Medusa and their expected payloads.',
}
},
]} />
---
## Automated RMA Flow
Business need to optimize their Return Merchandise Authorization (RMA) flow to ensure a good customer experience and service. By automating the flow, customers can request to return their received items, and businesses can quickly support them.
Medusas commerce features are geared towards automating RMA flows and ensuring a good customer experience.
For example, customers can create returns for their orders without direct involvement from the store operator. The store operator will then receive a notification regarding the return and handle it accordingly. The same applies to order exchanges.
Medusa also allows the store operator to edit orders, receive customer approval for the edits, and authorize additional payment if necessary, all within a seamless workflow.
Similar to the examples mentioned earlier, each of these actions trigger events that you can listen to and perform additional actions based on your use case.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/development/events',
label: 'Event Bus',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the event architecture system in the Medusa backend.',
}
},
{
type: 'link',
href: '/development/events/create-subscriber',
label: 'Create a Subscriber',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a subscriber to listen to events.',
}
},
{
type: 'link',
href: '/development/events/events-list',
label: 'Events Reference',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Check out triggered events in Medusa and their expected payloads.',
}
},
{
type: 'link',
href: '/modules/orders/returns',
label: 'Order Returns',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Order Returns architecture and features.',
}
},
{
type: 'link',
href: '/modules/orders/swaps',
label: 'Order Swaps',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Order Swaps architecture and features.',
}
},
{
type: 'link',
href: '/modules/orders/#order-edits',
label: 'Order Edits',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Order Edits architecture and features.',
}
},
]} />
---
## Customer Segmentation
Businesses use Customer Segmentation to oragnize customers into different groups, then apply different price rules to these groups. For example, you may group customers by their product preferences, the number of orders theyve placed, or geographical location.
Based on your use case and the logic of segmentation, you can use different Medusa automation development tools to detect a customers segment. Medusa also provides a Customer Groups feature that allows you to segment customers, whether you do it manually or automatically.
For example, if youre grouping together customers with more than twenty orders, you can use a Subscriber that listens to the `order.placed` event and checks the number of orders the customer has so far. Then, using Medusas Customer Groups feature, you can add that customer to the VIP group. Finally, you can utilize the Price Lists feature to provide different prices or discounts for customers in the VIP group.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/modules/customers/customer-groups',
label: 'Customer Groups',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Customer Groups architecture and features.',
}
},
{
type: 'link',
href: '/development/events',
label: 'Subscribers and Events',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about events in Medusa and how to listen to events.',
}
},
{
type: 'link',
href: '/modules/price-lists',
label: 'Price Lists',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Price Lists architecture and features.',
}
},
]} />
<details>
<summary>
Example: Add customer to VIP group
</summary>
Heres an example of a subscriber that listens to the `order.placed` event and checks if the customer should be added to the VIP customer group based on their number of orders:
```ts title=src/subscribers/add-custom-to-vip.ts
import {
CustomerGroupService,
CustomerService,
EventBusService,
OrderService,
} from "@medusajs/medusa"
type InjectedDependencies = {
orderService: OrderService
customerService: CustomerService
customerGroupService: CustomerGroupService
eventBusService: EventBusService
}
class AddCustomerToVipSubscriber {
protected orderService_: OrderService
protected customerService_: CustomerService
protected customerGroupService_: CustomerGroupService
constructor({
orderService,
customerService,
customerGroupService,
eventBusService,
}: InjectedDependencies) {
this.orderService_ = orderService
this.customerService_ = customerService
this.customerGroupService_ = customerGroupService
eventBusService.subscribe(
"order.placed",
this.handleOrderPlaced
)
}
handleOrderPlaced = async ({ id }) => {
// check if VIP group exists
const vipGroup = await this.customerGroupService_.list({
name: "VIP",
}, {
relations: ["customers"],
})
if (!vipGroup.length) {
return
}
// retrieve order and its customer
const order = await this.orderService_.retrieve(id)
if (!order || !order.customer_id ||
vipGroup[0].customers.find(
(customer) => customer.id === order.customer_id
) !== undefined) {
return
}
// retrieve orders of this customer
const [, count] = await this.orderService_.listAndCount({
customer_id: order.customer_id,
})
if (count >= 20) {
// add customer to VIP group
this.customerGroupService_.addCustomers(
vipGroup[0].id,
order.customer_id
)
}
}
}
export default AddCustomerToVipSubscriber
```
</details>
---
## Marketing Automation
In your commerce store, you may utilize marketing strategies that encourage customers to make purchases.
For example, you may send a newsletter when new products are added to your store. In Medusa, this can be handled by listening to the [product events](../development/events/events-list.md#product-events), such as `product.created`, using a Subscriber, then sending an email to subscribed customers with tools like [SendGrid](../plugins/notifications/sendgrid.mdx) or [Mailchimp](../plugins/notifications/mailchimp.md).
You can alternatively have a Scheduled Job that checks if the number of new products has exceeded a set threshold, then send out the newsletter.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/development/events',
label: 'Events and Subscribers',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about events in Medusa and how to listen to events.',
}
},
{
type: 'link',
href: '/development/scheduled-jobs/overview',
label: 'Scheduled Jobs',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about scheduled jobs and how you can create one.',
}
},
{
type: 'link',
href: '/development/events/events-list',
label: 'Events Reference',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Check out triggered events in Medusa and their expected payloads.',
}
},
]} />
<details>
<summary>
Example: Sending a newsletter email after adding ten products
</summary>
Heres an example of listening to the `product.created` event in a subscriber and send a newsletter if the condition is met:
```ts title=src/subscribers/send-products-newsletter.ts
import {
CustomerService,
EventBusService,
NoteService,
OrderService,
ProductService,
StoreService,
} from "@medusajs/medusa"
import {
ProductSelector,
} from "@medusajs/medusa/dist/types/product"
type InjectedDependencies = {
eventBusService: EventBusService
sendgridService: any
productService: ProductService
storeService: StoreService
customerService: CustomerService
}
class SendProductsNewsletterSubscriber {
protected sendGridService_: any
protected productService_: ProductService
protected storeService_: StoreService
protected customerService_: CustomerService
constructor({
eventBusService,
sendgridService,
productService,
storeService,
customerService,
}: InjectedDependencies) {
this.productService_ = productService
this.sendGridService_ = sendgridService
this.storeService_ = storeService
this.customerService_ = customerService
eventBusService.subscribe(
"product.created",
this.handleProductCreated
)
}
handleProductCreated = async ({ id }) => {
// retrieve store to have access to last send date
const store = await this.storeService_.retrieve()
const productFilters: ProductSelector = {}
if (store.metadata.last_send_date) {
productFilters.created_at = {
gt: new Date(store.metadata.last_send_date as string),
}
}
const products = await this.productService_.list(
productFilters
)
if (products.length > 10) {
// get subscribed customers
const customers = await this.customerService_.list({
metadata: {
is_subscribed: true,
},
})
this.sendGridService_.sendEmail({
templateId: "product-newsletter",
from: "hello@medusajs.com",
to: customers.map((customer) => ({
name: customer.first_name,
email: customer.email,
})),
data: {
// any data necessary for your template...
products,
},
})
await this.storeService_.update({
metadata: {
last_send_date: new Date(),
},
})
}
}
}
export default SendProductsNewsletterSubscriber
```
</details>
---
## Automation Development Toolkit
The use cases mentioned in this guide are just some examples of what commerce automation you can perform or implement with Medusa. Medusa provides the necessary development tools and mechanisms that allow you to automate tasks and manual work.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/development/events',
label: 'Events and Subscribers',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about events in Medusa and how to listen to events.',
}
},
{
type: 'link',
href: '/development/notification/overview',
label: 'Notification Service',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about notification services and how to create one.',
}
},
{
type: 'link',
href: '/development/scheduled-jobs/overview',
label: 'Scheduled Jobs',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about scheduled jobs and how you can create one.',
}
},
{
type: 'link',
href: '/plugins/notifications',
label: 'Notification Plugins',
customProps: {
icon: Icons['bolt-solid'],
description: 'Check out available notification plugins.',
}
},
]} />

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,4 @@
import DocCardList from '@theme/DocCardList';
import DocCard from '@theme/DocCard';
import Icons from '@theme/Icon';
import Feedback from '@site/src/components/Feedback';
import LearningPath from '@site/src/components/LearningPath';
@@ -31,75 +30,11 @@ Follow this recipe if you want to use Medusa for an ecommerce store. This recipe
---
## Recipe: Build a Marketplace
## Use-Case Based Recipes
Follow this guide if you want to build a Marketplace with Medusa.
Explore available recipes for different commerce use cases.
<DocCard item={{
type: 'link',
href: '/recipes/marketplace',
label: 'Build a Marketplace',
customProps: {
icon: Icons['building-storefront'],
description: 'Learn how you can build a marketplace with Medusa.'
}
}} />
---
## Recipe: Build Subscription Purchases
Follow this guide if you want to implement subscription-based purchases with Medusa.
<DocCard item={{
type: 'link',
href: '/recipes/subscriptions',
label: 'Build Subscription Purchases',
customProps: {
icon: Icons['credit-card-solid'],
description: 'Learn how you can implement subscription-based purchase in Medusa.'
}
}} />
---
## Recipe: Build B2B Store
Follow this guide if you want to build a B2B/Wholesale store.
<DocCard item={{
type: 'link',
href: '/recipes/b2b',
label: 'Build B2B Store',
customProps: {
icon: Icons['building-solid'],
description: 'Learn how you can build a B2B store in Medusa.'
}
}} />
<Feedback
event="survey_use_cases"
question="Did your find your use case?"
positiveQuestion="Is there anything that should improved?"
negativeQuestion="What was your use case?"
showLongForm={false}
/>
---
## Recipe: Build Multi-Region Store
Learn how you can build a multi-region store with Medusa.
<DocCard item={{
type: 'link',
href: '/recipes/multi-region',
label: 'Build Multi-Region Store',
customProps: {
icon: Icons['globe-europe-solid'],
description: 'Learn how you can build a multi-region store in Medusa.'
}
}} />
<DocCardList />
<Feedback
event="survey_use_cases"

View File

@@ -0,0 +1,126 @@
---
addHowToData: true
---
import DocCardList from '@theme/DocCardList';
import Icons from '@theme/Icon';
# Omnichannel Store
This document guides you through the different documentation resources that will help you build an omnichannel store with Medusa.
## Overview
An omnichannel store provides customers with a seamless shopping experience, no matter where theyre shopping from. Whether theyre buying your products from your online store, a marketplace like Amazon, or through social media, you should provide them with a good experience and handle orders consistently.
Medusas headless backend facilitates building an omnichannel store, as your backend and storefront arent tightly coupled. You can also utilize plugins and Medusas sales channels feature to expand your business into other avenues like marketplaces and social commerce.
---
## Create Multiple Storefronts with One Backend
When creating an omnichannel commerce store, youll likely build multiple webshops or mobile apps. All these storefronts should be able to provide your customers with a similar experience and allow them to browse products and place orders.
Medusas headless backend allows all storefronts to interact with Store REST APIs to provide the same commerce functionalities. This separation also gives you the freedom to choose your tech stack for the different storefronts youre creating.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/development/fundamentals/architecture-overview',
label: 'Medusas Architecture',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about Medusa\'s architecture and its ecosystem.',
}
},
{
type: 'link',
href: 'https://docs.medusajs.com/api/store',
label: 'Store REST APIs',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Check out available Store REST APIs in Medusa.',
}
},
]} />
---
## Integrate with Marketplaces and Social Commerce
Businesses are no longer bound to sell in their own stores. They can reach their customers through their different shopping channels.
One example is marketplaces like Amazon. Customers searching through Amazon to find products are inadvertently searching through a huge number of third-party stores connected to Amazons marketplace.
With Medusa, you can use the Sales Channels feature that allows you to set different product availability across sales channels. You can then integrate with Amazons seller program and use their APIs to push your products on Amazon. This integration can be achieved through a custom plugin that you create and install on your Medusa backend.
Another channel that attracts customer sales is social media. Customers browsing a social media app can now find products and buy them. With an approach similar to what was mentioned above, you can create a plugin in your Medusa backend that integrates with social media apps to show your products and sell them to customers on the app.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/modules/sales-channels/overview',
label: 'Sales Channels',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Sales Channel features.',
}
},
{
type: 'link',
href: '/development/plugins/create',
label: 'Create a Plugin',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a plugin.',
}
},
]} />
---
## Optimize Customer Experience
Each business has a unique brand and wants to provide customers with the best journey and experience. With Medusas modular architecture, businesses can focus on bringing their brands to life without any restrictions.
For your storefronts, you can implement the customer journey and design that leads to the best customer experience. The backend does not impose any restrictions on how the frontend is built.
Medusas architecture also makes it easier to integrate any third-party services necessary to provide a better customer experience with a plugin. This plugins functionality can be accessible to the storefronts connected to the Medusa backend.
For example, if youve integrated a search plugin such as Algolia in the Medusa backend, the storefronts can utilize it through the Search Products endpoint. Another example is installing the Stripe payment plugin on the backend, and utilizing it in your storefronts to make payments before placing an order.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/development/plugins/create',
label: 'Create a Plugin',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a plugin.',
}
},
{
type: 'link',
href: '/plugins/overview',
label: 'Official Plugins',
customProps: {
icon: Icons['bolt-solid'],
description: 'Check out available official plugins.',
}
},
{
type: 'link',
href: 'https://medusajs.com/plugins/',
label: 'Plugins Library',
customProps: {
icon: Icons['bolt-solid'],
description: 'Check out available community plugins.',
}
},
]} />
---
## Additional Development
You can find other resources for your omnichannel development in the [Medusa Development section](../development/overview.mdx) of this documentation.

View File

@@ -0,0 +1,237 @@
---
addHowToData: true
---
import DocCardList from '@theme/DocCardList';
import DocCard from '@theme/DocCard';
import Icons from '@theme/Icon';
# Order Management System (OMS)
This document guides you through the different features and resources available in Medusa to use it as an order management system (OMS).
## Overview
An order management system (OMS) is a system that provides features to track and manage orders and typically integrates with third-party services to handle payment, fulfillment, and more. Businesses use an OMS as part of a bigger commerce ecosystem that uses different services to achieve the business use case.
Medusa can be used within a larger ecosystem as an OMS. Its modular architecture and commerce features make it easy for developers to integrate it with other services while utilizing powerful OMS features, including returns, exchanges, and order edits.
---
## Source Orders into Medusa
Since an OMS is part of a larger ecosystem, your orders will likely come from different sources or channels. All these channels must ultimately direct their order to the OMS. This can be done in different ways in Medusa depending on your use case.
The basic way would be to use the REST APIs to create an order in Medusa. You can use the [Store REST APIs](https://docs.medusajs.com/api/store#carts), which are useful if the order is placed directly by the customer such as through a storefront. Alternatively, you can use the [Draft Orders](https://docs.medusajs.com/api/admin#draft-orders) feature that allows you to create the order without customer interference. This method can be helpful if youre creating the order through an automated script or from a channel managed by a store operator, such as a [POS](./pos.mdx).
If your use case is more advanced or complex, you can create a custom endpoint that gives you more control over how you create the order. For example, you can create a custom endpoint that allows creating or inserting a batch of orders.
You can also create a Scheduled Job to import orders into Medusa from an external service or system at a defined interval.
<DocCardList colSize={6} items={[
{
type: 'link',
href: 'https://docs.medusajs.com/api/store#carts',
label: 'Store REST APIs',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to use the Store REST APIs to create an order.',
}
},
{
type: 'link',
href: 'https://docs.medusajs.com/api/admin#draft-orders',
label: 'Draft Order APIs',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about available Draft Order Admin REST APIs.',
}
},
{
type: 'link',
href: '/development/endpoints/create',
label: 'Create Endpoint',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a custom endpoint in the Medusa backend.',
}
},
{
type: 'link',
href: '/development/scheduled-jobs/create',
label: 'Create Scheduled Jobs',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a scheduled job in the Medusa backend.',
}
},
]} />
---
## Route Orders to Third-party Fulfillment Services
In your ecosystem, you have different third-party services and tools that handle the fulfillment of orders. The OMS integrates with these services to ensure theyre used when fulfillment events occur.
With Medusa, you can integrate third-party fulfillment services either by creating a fulfillment provider or installing an existing fulfillment plugin. The fulfillment provider must implement different methods that are used when fulfillment actions are taken on the order.
For example, when an admin creates a fulfillment on an order, the method defined in the fulfillment provider associated with the order is executed. In that method, you can create the necessary implementation that handles creating the fulfillment in the third-party service.
In addition, Medusa has an event bus that allows you to listen to events and perform an action asynchronously when that event is triggered. So, you can listen to fulfillment-related events, such as the `order.fulfillment_created` event, and handle that event in the subscribed method when its triggered.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/modules/carts-and-checkout/backend/add-fulfillment-provider',
label: 'Create a Fulfillment Provider',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a fulfillment provider in Medusa.',
}
},
{
type: 'link',
href: 'https://docs.medusajs.com/api/admin#draft-orders',
label: 'Events',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the event bus and how to listen to events.',
}
},
]} />
---
## Process Payment with Third-Party Providers
Similar to fulfillment services, youll also have payment providers that handle processing payments. Your OMS integrates with these providers to handle payment-related actions.
Medusa allows you to integrate third-party payment providers by creating a payment processor. The payment processor must implement different methods that are used when the orders payment is being processed, such as when its captured or refunded.
Alternatively, you can use existing payment plugins. Medusa provides official payment plugins for [Stripe](../plugins/payment/stripe.mdx), [PayPal](../plugins/payment/paypal.md), and [Klarna](../plugins/payment/klarna.md).
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/plugins/payment',
label: 'Payment Plugins',
customProps: {
icon: Icons['bolt-solid'],
description: 'Check out available official payment plugins.',
}
},
{
type: 'link',
href: '/modules/carts-and-checkout/backend/add-payment-provider',
label: 'Create a Payment Processor',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a payment processor.',
}
},
]} />
---
## Handle Returns, Exchanges, and Edits
Medusa provides advanced order features that make it an ideal OMS choice and allow you to provide a great customer experience.
Items in an order can be returned or exchanged. The return or exchange can either be requested by the customer or created by an admin. Once created, they reflect changes in the orders total and inventory and allow the admin to issue a refund to the customer as well if necessary. In the case of exchanges, the fulfillment provider will be used to fulfill the new item sent to the customer.
Orders can also be edited to add, update, or delete items in an order. Additional payment can be authorized, or a refund can be issued, if necessary. Once an order edit is confirmed, the changes are reflected on the orders totals and inventory.
These features can be used through the [Admin](https://docs.medusajs.com/api/admin) and [Store REST APIs](https://docs.medusajs.com/api/store). You can also perform these actions in your custom endpoints or services using the [core services](../references/services/index.md) and their methods.
Once these actions occur, events, such as `order.return_requested` are triggered by Medusas event bus. So, you can listen to different events to perform asynchronous actions, for example, to communicate with third-party services or tools.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/modules/orders/returns',
label: 'Order Returns',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Order Return architecture and features.',
}
},
{
type: 'link',
href: '/modules/orders/swaps',
label: 'Exchanges (Swaps)',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Exchange or Swap architecture and features.',
}
},
{
type: 'link',
href: '/modules/orders#order-edits',
label: 'Order Edits',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Order Edit feature and how it works.',
}
},
{
type: 'link',
href: '/development/events/events-list',
label: 'Event Reference',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Check out triggered events in Medusa and their payloads.',
}
},
]} />
---
## Track Inventory Across Sales Channels
An OMS typically connects to more than one sales channel, such as one or more storefronts and a POS. Its important to keep track of your inventory across these sales channels.
Medusas multi-warehouse and sales channel features allow you to track inventory levels across different stock locations, which are tied to sales channels. When an order is placed, an item in a stock location, based on the orders sales channel, is reserved. Once the item is fulfilled, the reserved quantity is deducted from the items inventory quantity.
The inventory is also changed when an item is returned, exchanged, or when an order is edited.
Medusas inventory and stock location modules that power its multi-warehouse features can also be completely replaced with a custom implementation. This allows you to take control of how inventory functionalities are implemented in Medusa.
In addition, you can integrate third-party inventory systems by creating or installing a plugin. Medusa provides an official [Brightpearl](https://github.com/medusajs/medusa/tree/develop/packages/medusa-plugin-brightpearl) plugin that syncs orders and inventory with Brightpearl.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/modules/multiwarehouse/overview',
label: 'Multi-warehouse',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Multi-warehouse architecture and features.',
}
},
{
type: 'link',
href: '/modules/sales-channels/overview',
label: 'Sales Channels',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Sales Channel architecture and features.',
}
},
{
type: 'link',
href: '/development/plugins/create',
label: 'Create a Plugin',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a plugin that can be installed in a Medusa backend.',
}
},
]} />
---
## Additional Development and Commerce Features
Medusa provides more commerce features that you can learn about in the [Commerce Modules](../modules/overview.mdx) section of this documentation.
Medusa is also completely customizable, and you can learn more about customizing it in the [Medusa Development](../development/overview.mdx) section of this documentation.

View File

@@ -0,0 +1,166 @@
---
addHowToData: true
---
import DocCardList from '@theme/DocCardList';
import Icons from '@theme/Icon';
# Personalized Products
This document guides you through the different documentation resources that will help you build personalized products with Medusa.
## Overview
Commerce stores that provide personalized products allow customers to pick and choose how the product looks or what features it includes. For example, they can upload an image to print on a shirt or provide a message to include in a letter.
Medusas customizable architecture allows you to customize its entities or create your own to implement and store personalized products. Also, as the Medusa backend is headless, you have freedom in how you choose to implement the storefront. This is essential for ecommerce stores that provide personalized products, as you typically build a unique experience around your products.
---
## Store Personalized Data
Most of the entities in Medusas core include a `metadata` attribute. This attribute is helpful for storing custom data in the core entities.
The `Product` entity represents the main product, whereas the `ProductVariant` is the different saleable options of that product. For example, a shirt is a `Product`, and each different color of the shirt is the `ProductVariant`. The `LineItem` entity is the product variant added to the cart.
So, you can use the `metadata` attribute of the `LineItem` entity to store the customers personalization. Optionally, you can use the `metadata` attribute in the `Product` or `ProductVariant` to store the expected format of personalized data. This depends on your use case and how basic or complex it is.
For example, if youre asking customers to enter a message to put in a letter theyre purchasing, you can use the `metadata` attribute of the `LineItem` entity to set the personalized information entered by the customer.
In more complex cases, you can extend entities from the core, such as the `Product` entity, to add more attributes. You can also create new custom entities to hold your personalized data and logic.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/development/entities/overview#metadata-attribute',
label: 'Metadata Attribute',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the metadata attribute and how to use it.',
}
},
{
type: 'link',
href: '/development/entities/create',
label: 'Create an Entity',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create an entity in the Medusa backend.',
}
},
{
type: 'link',
href: '/development/entities/extend-entity',
label: 'Extend an Entity',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to extend an entity in the Medusa backend.',
}
},
]} />
---
## Build a Custom Storefront
Medusa provides a headless backend that can be accessed through REST APIs. So, there are no restrictions in what language or framework you use to build the storefront, or what design or experience you provide to customers.
You can build a unique experience around your products that focuses on the customers personalization capabilities.
Medusa provides a Next.js storefront starter with basic ecommerce functionalities that can be used and modified. You can also build your own storefront by using Medusas client libraries or REST APIs to communicate with the backend from the storefront.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/starters/nextjs-medusa-starter',
label: 'Next.js Starter',
customProps: {
icon: Icons['nextjs'],
description: 'Learn about the Next.js starter and how to install it.',
}
},
{
type: 'link',
href: '/storefront/roadmap',
label: 'Build Your Own Storefront',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Follow this roadmap to learn how to create a storefront.',
}
},
]} />
---
## Pass Personalized Data to the Order
If you followed the basic approach of using the `metadata` attribute to store the personalized data, you can pass the personalization data when you add an item to the cart in the storefront using the [Add a Line Item](https://docs.medusajs.com/api/store#carts_postcartscartlineitems) endpoint. This endpoint accepts a `metadata` request body parameter that will be stored in the created line items `metadata` attribute.
In the case that youve created a custom entity or extended a core entity, you can create a custom endpoint that handles saving the personalization data. You can then call that endpoint from the storefront before or after adding the item to the cart.
<DocCardList colSize={6} items={[
{
type: 'link',
href: 'https://docs.medusajs.com/api/store#carts_postcartscartlineitems',
label: 'Add a Line Item Endpoint',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the expected request parameters and response.',
}
},
{
type: 'link',
href: '/development/endpoints/create',
label: 'Create Endpoint',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create an endpoint in the Medusa backend.',
}
},
]} />
---
## Access Personalized Data in the Order
If you stored the personalized data in the `metadata` of the line items, those same line items are associated with the placed order. So, by expanding the `items` relation on the `Order` entity, you can retrieve the `metadata` attribute of the line items.
In the case that youve created a custom entity or extended a core entity, you can create a custom endpoint that handles retrieving the personalization data. If the entity youve created or customized is associated with the Order entity, you can alternatively expand it similarly to the `items` relation.
If you want to show the personalized data in the Medusa admin, you can extend the Medusa admin to add a widget, a UI route, or a setting page, and show the personalized data.
<DocCardList colSize={4} items={[
{
type: 'link',
href: 'https://docs.medusajs.com/api/store#expanding-fields',
label: 'Expanding Relations in API Requests',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to expand relations in API requests.',
}
},
{
type: 'link',
href: '/development/services/create-service#pagination-filtering-and-relations',
label: 'Expanding Relations in Services',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to expand relations in services.',
}
},
{
type: 'link',
href: '/admin/widgets',
label: 'Extending Medusa Admin',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to extend the Medusa admin with widgets and more.',
}
},
]} />
---
## Additional Development
You can find other resources for your personalized products development in the [Medusa Development section](../development/overview.mdx) of this documentation.

View File

@@ -0,0 +1,305 @@
---
addHowToData: true
---
import DocCardList from '@theme/DocCardList';
import Icons from '@theme/Icon';
# POS
This document guides you through the different features and resources available in Medusa to create a point-of-sale (POS) system.
## Overview
A POS system can be used in a businesss retail or offline stores to access and manage products and their inventories, and place orders for customers. Based on your use case, you can provide more features that can improve the customer experience. For example, customer discounts or Return Merchandise Authorization (RMA) features.
Medusas architecture, commerce features, and customization capabilities allow you to build a POS system without any limitations or restrictions.
Medusas headless backend facilitates creating any type of frontend that can communicate with the backend, including a POS system. Also, Medusas commerce features, including mutli-warehouse, sales channels, and order management features, can power your POS system to provide essential features for both store operators and customers making their purchase.
:::tip
Recommended read: [How Tekla built a POS system with Medusa](https://medusajs.com/blog/tekla-agilo-pos-case/).
:::
---
## Freedom in Choosing Your POS Tech Stack
When you decide to build a POS system, you have to make an important choice of which programming framework, language, or tool you want to use. In most cases, this can be interdependent on the commerce engine, as it can limit your choices.
Medusas modular architecture removes any restrictions you may have while making this choice. Regardless of what you choose, any client or front end can connect to the Medusa backend using its headless REST APIs. So, when building the POS system, youll be interacting with the [Admin REST APIs](https://docs.medusajs.com/api/admin).
For example, you can use [Expo](https://expo.dev/) with [React Native](https://reactnative.dev/) to build a cross-platform POS app. In this case, you can also utilize [Medusas JavaScript client](../js-client/overview.md) to make it even easier to send requests to the backend.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/development/fundamentals/architecture-overview',
label: 'Medusas Architecture',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about Medusa\'s architecture and its ecosystem.',
}
},
{
type: 'link',
href: 'https://docs.medusajs.com/api/admin',
label: 'Admin REST APIs',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Check out available Admin REST APIs in Medusa.',
}
},
{
type: 'link',
href: '/js-client/overview',
label: 'JavaScript Client',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the JavaScript client and to use it.',
}
},
]} />
---
## Integrate a Barcode Scanner
An essential feature a POS system needs is the capability to search and find products by scanning their barcode. You can then check their inventory information or add them to the customers order.
Medusas [Product Variant entity](../references/entities/classes/ProductVariant.md), which represents a saleable stock item, already includes the necessary attributes to implement this integration, mainly the `barcode` attribute. Other notable attributes include `ean`, `upc`, and `hs_code`, among others.
To search through product variants by their barcode, you can create a custom endpoint and use it within your POS. The endpoint can receive the items barcode, and return all product variants having that barcode.
You can also create another custom endpoint that allows you to scan products in your store by their barcode and automatically add them to your backend. This eliminates the need to enter your product details manually.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/modules/products',
label: 'Products',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Product architecture and features.',
}
},
{
type: 'link',
href: '/development/endpoints/create',
label: 'Create Endpoint',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create an endpoint in the Medusa backend.',
}
},
]} />
<details>
<summary>
Example: Search Products By Barcode Endpoint
</summary>
Heres an example of creating a custom endpoint that searches product variants by a barcode:
```ts title=src/api/index.ts
import { Request, Response, Router } from "express"
import cors from "cors"
import {
ConfigModule,
errorHandler,
ProductVariantService,
wrapHandler,
} from "@medusajs/medusa"
import { getConfigFile } from "medusa-core-utils"
import { MedusaError } from "@medusajs/utils"
export default (rootDirectory: string): Router | Router[] => {
// Read currently-loaded medusa config
const { configModule } = getConfigFile<ConfigModule>(
rootDirectory,
"medusa-config"
)
const { projectConfig } = configModule
// Set up our CORS options objects, based on config
const storeCorsOptions = {
origin: projectConfig.store_cors.split(","),
credentials: true,
}
// Set up express router
const router = Router()
router.get(
"/store/search-barcode",
cors(storeCorsOptions),
wrapHandler(
async (req: Request, res: Response) => {
const barcode = (req.query.barcode as string) || ""
if (!barcode) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Barcode is required"
)
}
// get product service
const productVariantService = req.scope.resolve<
ProductVariantService
>("productVariantService")
// retrieve product variants by barcode
const productVariants = await productVariantService
.list({
barcode,
})
res.json({
product_variants: productVariants,
})
}
)
)
router.use(errorHandler())
return router
}
```
</details>
---
## Access Accurate Inventory Details
As you manage an online and offline store, its important to make a separation between inventory quantity across different locations. For example, when an online order is made, the change in the inventory quantity of the order items should be made from the warehouses inventory, and not from the retail stores.
Medusas multi-warehouse features allow you to manage the inventory items and their availability across locations and sales channels. You can create a sales channel for your online store and a sales channel for your POS system, then manage the inventory quantity of product variants in each of those sales channels. You can also have different sales channels for different retail stores that use the POS system.
When a customer browses your online store and wants to make a purchase, they can only buy items that are available in stock in the location associated with the online stores channel.
In the POS system, you can use the admin [stock location](https://docs.medusajs.com/api/admin#stock-locations) and [inventory item APIs](https://docs.medusajs.com/api/admin#inventory-items) to check whether an item is available in inventory or not. This helps store operators provide better and quicker customer service.
This also opens the door for other business opportunities, such as an endless aisle experience. If a product isnt available in-store but is available in other warehouses, you can allow a customer to purchase that item in-store and have it delivered to their address.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '/modules/multiwarehouse/overview',
label: 'Multi-Warehouse',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Multi-warehouse architecture and features.',
}
},
{
type: 'link',
href: '/modules/sales-channels/overview',
label: 'Sales Channels',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Sales Channel architecture and features.',
}
},
{
type: 'link',
href: '/modules/multiwarehouse/admin/manage-inventory-items',
label: 'Manage Inventory Items',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to use the Admin REST APIs to manage inventory items.',
}
},
]} />
---
## Build an Omni-channel Customer Experience
A customer making a purchase in-store should have the same benefits as an online customer. You can find their customer details, if theyre registered in the ecommerce store, and provide them with applicable discounts if necessary.
Using Medusas Customer APIs and features, you can easily query customers and place an order under their account. The customer can then view their order details on their profile as if they had placed the order online.
In addition, using Medusas dynamic discounts feature, store operators can create discounts on the fly for customers using the POS system and apply them to their orders. This improves customer experience and builds customer loyalty.
You can further customize your setup to provide a better customer experience. For example, you can create a rewards system or loyalty points that your customers can benefit from when they make purchases either through the POS system or the online store.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/modules/customers/overview',
label: 'Customers',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Customer architecture and features.',
}
},
{
type: 'link',
href: '/modules/discounts/overview',
label: 'Discounts',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Discount architecture and features.',
}
},
]} />
---
## Accept Payment, Place Order, and Use RMA Features
The first element to placing an order is accepting the customers payment. This is handled differently based on the payment methods you want to provide.
Medusa provides a [manual payment processor](https://github.com/medusajs/medusa/tree/develop/packages/medusa-payment-manual) with a minimal implementation that assumes merchants handle all payment operations manually. Alternatively, you can integrate payment processors that allow you to accept in-store payments, such as [Stripe Terminal](https://stripe.com/terminal), by creating a payment processor.
To place an order in the POS system, you can use the [Draft Order APIs](https://docs.medusajs.com/api/admin#draft-orders). This would allow the store operator to place the order under the customers account if theyre registered, and add all the necessary details related to discounts and more, similar to placing an order through the online store.
Using the Medusa admin dashboard, merchants can view all orders coming from different sales channels. This keeps logistics and order handling consistent throughout orders. This also allows customers who place their order in-store to benefit from features like returns and exchanges or swaps that are already available for online store orders.
<DocCardList colSize={6} items={[
{
type: 'link',
href: '/modules/carts-and-checkout/backend/add-payment-provider',
label: 'Create a Payment Processor',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to create a payment processor.',
}
},
{
type: 'link',
href: '/modules/orders/draft-orders',
label: 'Draft Orders',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Draft Order architecture and features.',
}
},
{
type: 'link',
href: '/modules/orders/returns',
label: 'Order Returns',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Order Return architecture and features.',
}
},
{
type: 'link',
href: '/modules/orders/swaps',
label: 'Order Swaps',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn about the Order Swap architecture and features.',
}
},
]} />
---
## Additional Development
You can find other resources for your POS development in the [Medusa Development section](../development/overview.mdx) of this documentation.

View File

@@ -51,21 +51,81 @@ module.exports = {
type: "doc",
id: "recipes/marketplace",
label: "Marketplace",
customProps: {
iconName: "building-storefront",
},
},
{
type: "doc",
id: "recipes/subscriptions",
label: "Subscriptions",
customProps: {
iconName: "credit-card-solid",
},
},
{
type: "doc",
id: "recipes/commerce-automation",
label: "Commerce Automation",
customProps: {
iconName: "clock-solid-mini",
},
},
{
type: "doc",
id: "recipes/oms",
label: "Order Management System",
customProps: {
iconName: "check-circle-solid",
},
},
{
type: "doc",
id: "recipes/pos",
label: "POS",
customProps: {
iconName: "computer-desktop-solid",
},
},
{
type: "doc",
id: "recipes/digital-products",
label: "Digital Products",
customProps: {
iconName: "photo-solid",
},
},
{
type: "doc",
id: "recipes/personalized-products",
label: "Personalized Products",
customProps: {
iconName: "swatch-solid",
},
},
{
type: "doc",
id: "recipes/b2b",
label: "B2B / Wholesale",
customProps: {
iconName: "building-solid",
},
},
{
type: "doc",
id: "recipes/multi-region",
label: "Multi-Region Store",
customProps: {
iconName: "globe-europe-solid",
},
},
{
type: "doc",
id: "recipes/omnichannel",
label: "Omnichannel Store",
customProps: {
iconName: "channels-solid",
},
},
],
},
@@ -2408,6 +2468,16 @@ module.exports = {
"Learn how to integrate ipstack to access the user's region.",
},
},
{
type: "doc",
id: "plugins/other/restock-notifications",
label: "Restock Notifications",
customProps: {
iconName: "bolt-solid",
description:
"Learn how to integrate restock notifications with the Medusa backend.",
},
},
{
type: "doc",
id: "plugins/other/discount-generator",

View File

@@ -0,0 +1,30 @@
import React from "react"
import { IconProps } from ".."
const IconPhotoSolid: React.FC<IconProps> = ({
iconColorClassName,
...props
}) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.25 5C1.25 4.50272 1.44754 4.02581 1.79917 3.67417C2.15081 3.32254 2.62772 3.125 3.125 3.125H16.875C17.3723 3.125 17.8492 3.32254 18.2008 3.67417C18.5525 4.02581 18.75 4.50272 18.75 5V15C18.75 15.4973 18.5525 15.9742 18.2008 16.3258C17.8492 16.6775 17.3723 16.875 16.875 16.875H3.125C2.62772 16.875 2.15081 16.6775 1.79917 16.3258C1.44754 15.9742 1.25 15.4973 1.25 15V5ZM2.5 13.3833V15C2.5 15.345 2.78 15.625 3.125 15.625H16.875C17.0408 15.625 17.1997 15.5592 17.3169 15.4419C17.4342 15.3247 17.5 15.1658 17.5 15V13.3833L15.2583 11.1425C15.024 10.9084 14.7063 10.7769 14.375 10.7769C14.0437 10.7769 13.726 10.9084 13.4917 11.1425L12.7583 11.875L13.5667 12.6833C13.6281 12.7406 13.6773 12.8096 13.7115 12.8862C13.7456 12.9629 13.764 13.0456 13.7655 13.1296C13.767 13.2135 13.7515 13.2968 13.7201 13.3747C13.6887 13.4525 13.6419 13.5232 13.5825 13.5825C13.5232 13.6419 13.4525 13.6887 13.3747 13.7201C13.2968 13.7515 13.2135 13.767 13.1296 13.7655C13.0456 13.764 12.9629 13.7456 12.8862 13.7115C12.8096 13.6773 12.7406 13.6281 12.6833 13.5667L8.38333 9.2675C8.14896 9.03342 7.83125 8.90193 7.5 8.90193C7.16875 8.90193 6.85104 9.03342 6.61667 9.2675L2.5 13.3842V13.3833ZM10.9375 6.875C10.9375 6.62636 11.0363 6.3879 11.2121 6.21209C11.3879 6.03627 11.6264 5.9375 11.875 5.9375C12.1236 5.9375 12.3621 6.03627 12.5379 6.21209C12.7137 6.3879 12.8125 6.62636 12.8125 6.875C12.8125 7.12364 12.7137 7.3621 12.5379 7.53791C12.3621 7.71373 12.1236 7.8125 11.875 7.8125C11.6264 7.8125 11.3879 7.71373 11.2121 7.53791C11.0363 7.3621 10.9375 7.12364 10.9375 6.875Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconPhotoSolid

View File

@@ -1,7 +1,10 @@
import React from "react"
import { IconProps } from ".."
const IconPlusMini = ({ iconColorClassName, ...props }: IconProps) => {
const IconPlusMini: React.FC<IconProps> = ({
iconColorClassName,
...props
}) => {
return (
<svg
width={props.width || 20}

View File

@@ -70,6 +70,8 @@ import IconMap from "./Map"
import IconNewspaper from "./Newspaper"
import IconNextjs from "./Nextjs"
import IconPencilSquareSolid from "./PencilSquareSolid"
import IconPhotoSolid from "./PhotoSolid"
import IconPlusMini from "./PlusMini"
import IconPuzzle from "./Puzzle"
import IconPuzzleSolid from "./PuzzleSolid"
import IconReact from "./React"
@@ -181,6 +183,8 @@ export default {
newspaper: IconNewspaper,
nextjs: IconNextjs,
"pencil-square-solid": IconPencilSquareSolid,
"photo-solid": IconPhotoSolid,
"plus-mini": IconPlusMini,
puzzle: IconPuzzle,
"puzzle-solid": IconPuzzleSolid,
react: IconReact,