docs: added new recipes (#4964)
* docs: added new recipes * added oms recipe * address PR feedback
This commit is contained in:
177
www/docs/content/plugins/other/restock-notifications.md
Normal file
177
www/docs/content/plugins/other/restock-notifications.md
Normal file
@@ -0,0 +1,177 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
# Restock Notifications Plugin
|
||||
|
||||
In this document, you’ll 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`.
|
||||
689
www/docs/content/recipes/commerce-automation.mdx
Normal file
689
www/docs/content/recipes/commerce-automation.mdx
Normal 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 store’s 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 Medusa’s Notification Service, you can handle notifications triggered from actions on the customer’s 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>
|
||||
|
||||
Here’s 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, you’ll 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>
|
||||
|
||||
Here’s 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 it’s 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 Medusa’s 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.
|
||||
|
||||
Medusa’s 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 they’ve 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 customer’s segment. Medusa also provides a Customer Groups feature that allows you to segment customers, whether you do it manually or automatically.
|
||||
|
||||
For example, if you’re 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 Medusa’s 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>
|
||||
|
||||
Here’s 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>
|
||||
|
||||
Here’s 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.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
1080
www/docs/content/recipes/digital-products.mdx
Normal file
1080
www/docs/content/recipes/digital-products.mdx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
126
www/docs/content/recipes/omnichannel.mdx
Normal file
126
www/docs/content/recipes/omnichannel.mdx
Normal 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 they’re shopping from. Whether they’re 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.
|
||||
|
||||
Medusa’s headless backend facilitates building an omnichannel store, as your backend and storefront aren’t tightly coupled. You can also utilize plugins and Medusa’s 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, you’ll 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.
|
||||
|
||||
Medusa’s 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 you’re creating.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/fundamentals/architecture-overview',
|
||||
label: 'Medusa’s 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 Amazon’s 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 Amazon’s 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 Medusa’s 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.
|
||||
|
||||
Medusa’s architecture also makes it easier to integrate any third-party services necessary to provide a better customer experience with a plugin. This plugin’s functionality can be accessible to the storefronts connected to the Medusa backend.
|
||||
|
||||
For example, if you’ve 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.
|
||||
237
www/docs/content/recipes/oms.mdx
Normal file
237
www/docs/content/recipes/oms.mdx
Normal 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 you’re 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 they’re 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 it’s 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, you’ll 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 order’s payment is being processed, such as when it’s 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 order’s 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 order’s 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 Medusa’s 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. It’s important to keep track of your inventory across these sales channels.
|
||||
|
||||
Medusa’s 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 order’s sales channel, is reserved. Once the item is fulfilled, the reserved quantity is deducted from the item’s inventory quantity.
|
||||
|
||||
The inventory is also changed when an item is returned, exchanged, or when an order is edited.
|
||||
|
||||
Medusa’s 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.
|
||||
166
www/docs/content/recipes/personalized-products.mdx
Normal file
166
www/docs/content/recipes/personalized-products.mdx
Normal 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.
|
||||
|
||||
Medusa’s 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 Medusa’s 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 customer’s 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 you’re asking customers to enter a message to put in a letter they’re 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 customer’s 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 Medusa’s 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 item’s `metadata` attribute.
|
||||
|
||||
In the case that you’ve 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 you’ve created a custom entity or extended a core entity, you can create a custom endpoint that handles retrieving the personalization data. If the entity you’ve 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.
|
||||
305
www/docs/content/recipes/pos.mdx
Normal file
305
www/docs/content/recipes/pos.mdx
Normal 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 business’s 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.
|
||||
|
||||
Medusa’s architecture, commerce features, and customization capabilities allow you to build a POS system without any limitations or restrictions.
|
||||
|
||||
Medusa’s headless backend facilitates creating any type of frontend that can communicate with the backend, including a POS system. Also, Medusa’s 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.
|
||||
|
||||
Medusa’s 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, you’ll 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 [Medusa’s 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: 'Medusa’s 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 customer’s order.
|
||||
|
||||
Medusa’s [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 item’s 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>
|
||||
|
||||
Here’s 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, it’s 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 warehouse’s inventory, and not from the retail store’s.
|
||||
|
||||
Medusa’s 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 store’s 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 isn’t 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 they’re registered in the ecommerce store, and provide them with applicable discounts if necessary.
|
||||
|
||||
Using Medusa’s 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 Medusa’s 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 customer’s 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 customer’s account if they’re 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.
|
||||
@@ -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",
|
||||
|
||||
30
www/docs/src/theme/Icon/PhotoSolid/index.tsx
Normal file
30
www/docs/src/theme/Icon/PhotoSolid/index.tsx
Normal 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
|
||||
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user