docs: create docs workspace (#5174)
* docs: migrate ui docs to docs universe * created yarn workspace * added eslint and tsconfig configurations * fix eslint configurations * fixed eslint configurations * shared tailwind configurations * added shared ui package * added more shared components * migrating more components * made details components shared * move InlineCode component * moved InputText * moved Loading component * Moved Modal component * moved Select components * Moved Tooltip component * moved Search components * moved ColorMode provider * Moved Notification components and providers * used icons package * use UI colors in api-reference * moved Navbar component * used Navbar and Search in UI docs * added Feedback to UI docs * general enhancements * fix color mode * added copy colors file from ui-preset * added features and enhancements to UI docs * move Sidebar component and provider * general fixes and preparations for deployment * update docusaurus version * adjusted versions * fix output directory * remove rootDirectory property * fix yarn.lock * moved code component * added vale for all docs MD and MDX * fix tests * fix vale error * fix deployment errors * change ignore commands * add output directory * fix docs test * general fixes * content fixes * fix announcement script * added changeset * fix vale checks * added nofilter option * fix vale error
This commit is contained in:
842
www/apps/docs/content/modules/orders/admin/edit-order.mdx
Normal file
842
www/apps/docs/content/modules/orders/admin/edit-order.mdx
Normal file
@@ -0,0 +1,842 @@
|
||||
---
|
||||
description: 'Learn how to implement order-editing features for admins using the REST APIs. This guide includes how to create an order edit and move order edit to request state, and more.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Edit an Order
|
||||
|
||||
In this document, you’ll learn how to create an order edit using the Admin API endpoints.
|
||||
|
||||
## Overview
|
||||
|
||||
The Admin API can be used to edit a customer’s order using the Order Editing feature.
|
||||
|
||||
The following changes can be made on an order:
|
||||
|
||||
- Add a new item to the original order
|
||||
- Edit an item’s quantity in the original order.
|
||||
- Delete an item from the original order.
|
||||
|
||||
Medusa then takes care of the calculation of subtotals, taxes, and more.
|
||||
|
||||
The Order Edit can then either be confirmed using the Storefront API as a customer, or force-confirmed using the Admin API as a merchant.
|
||||
|
||||
The changes are only reflected on the original order once the Order Edit is confirmed.
|
||||
|
||||

|
||||
|
||||
### Scenario
|
||||
|
||||
You want to add or use the following admin functionalities related to Order Editing:
|
||||
|
||||
- Create an order edit.
|
||||
- Add, edit, and delete items from an order.
|
||||
- Revert an item change in an order edit.
|
||||
- Move order edit into request state.
|
||||
- Force-confirm an order edit.
|
||||
|
||||
:::note
|
||||
|
||||
You can perform other functionalities related to order editing. To learn more, check out the [API reference](https://docs.medusajs.com/api/admin#order-edits).
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client](../../../js-client/overview.md) installed and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
### Authenticated Admin User
|
||||
|
||||
You must be an authenticated admin user before following along with the steps in the tutorial.
|
||||
|
||||
You can learn more about [authenticating as an admin user in the API reference](https://docs.medusajs.com/api/admin#authentication).
|
||||
|
||||
### Previous Steps
|
||||
|
||||
You must have an existing order that you want to edit.
|
||||
|
||||
---
|
||||
|
||||
## Create an Order Edit
|
||||
|
||||
Before you can start making changes to an order, you have to create a new order edit.
|
||||
|
||||
To do that, send a request to the [Create an OrderEdit](https://docs.medusajs.com/api/admin#order-edits_postorderedits) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orderEdits.create({
|
||||
order_id, // required
|
||||
})
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCreateOrderEdit } from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const createOrderEdit = useAdminCreateOrderEdit()
|
||||
|
||||
const handleCreateOrderEdit = (orderId: string) => {
|
||||
createOrderEdit.mutate({
|
||||
order_id: orderId,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/order-edits`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
order_id,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/order-edits' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"order_id": "<ORDER_ID>"
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint has one required request body parameter `order_id` which is the ID of the order this edit is being created for.
|
||||
|
||||
This request returns the Order Edit under the `order_edit` property.
|
||||
|
||||
:::info
|
||||
|
||||
You can only create one Order Edit at a time. So, if you try to create a new Order Edit for an order that is already being edited, you will receive an error.
|
||||
|
||||
:::info
|
||||
|
||||
---
|
||||
|
||||
## Make Changes to an Order’s Items
|
||||
|
||||
You can add new items into the original order, edit existing item in the original order, or delete items in the original order.
|
||||
|
||||
:::info
|
||||
|
||||
You can only make changes to items that have not been fulfilled yet in the order.
|
||||
|
||||
:::
|
||||
|
||||
### Add an Item
|
||||
|
||||
To add a new item to the original order, send a request to the [Add Line Item](https://docs.medusajs.com/api/admin#order-edits_postordereditseditlineitems) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orderEdits.addLineItem(orderEditId, {
|
||||
quantity: 1,
|
||||
variant_id,
|
||||
})
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminOrderEditAddLineItem } from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const addLineItem = useAdminOrderEditAddLineItem(orderEditId)
|
||||
|
||||
const handleAddLineItem =
|
||||
(quantity: number, variantId: string) => {
|
||||
addLineItem.mutate({
|
||||
quantity,
|
||||
variant_id: variantId,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/order-edits/${orderEditId}/items`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
quantity: 1,
|
||||
variant_id,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/order-edits/<ORDER_EDIT_ID>/items' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"quantity": 1,
|
||||
"variant_id": "<VARIANT_ID>"
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request requires the ID of the order edit as a path parameter.
|
||||
|
||||
In the body of the request, you pass the two parameters `quantity` and `variant_id` which will be used to add a new item into the original order.
|
||||
|
||||
This request returns the Order Edit object. You can access returned item changes using `order_edit.changes`.
|
||||
|
||||
### Update an Item
|
||||
|
||||
You can edit an item’s quantity in the original order.
|
||||
|
||||
To update an item, send a request to the [Update Line Item](https://docs.medusajs.com/api/admin#order-edits_postordereditseditlineitemslineitem) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orderEdits.updateLineItem(orderEditId, itemId, {
|
||||
quantity: 2,
|
||||
})
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminOrderEditUpdateLineItem } from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const updateLineItem = useAdminOrderEditUpdateLineItem(
|
||||
orderEditId,
|
||||
itemId
|
||||
)
|
||||
|
||||
const handleUpdateLineItem = (quantity: number) => {
|
||||
updateLineItem.mutate({
|
||||
quantity,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/order-edits/${orderEditId}/items/${itemId}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
quantity: 2,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/order-edits/<ORDER_EDIT_ID>/items/<ITEM_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"quantity": 2
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request requires the ID of the order edit and the ID of the item in the original order as path parameters.
|
||||
|
||||
In the body of the request, you can pass the `quantity` parameter, with its value being the new item quantity. In this example, you change the quantity of the item to `2`.
|
||||
|
||||
This request returns the Order Edit object. You can access returned item changes using `order_edit.changes`.
|
||||
|
||||
### Remove an Item
|
||||
|
||||
You can remove an item from the original order by sending a request to the [Remove Line Item](https://docs.medusajs.com/api/admin#order-edits_deleteordereditsordereditlineitemslineitem) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orderEdits.removeLineItem(orderEditId, itemId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminOrderEditDeleteLineItem } from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const removeLineItem = useAdminOrderEditDeleteLineItem(
|
||||
orderEditId,
|
||||
itemId
|
||||
)
|
||||
|
||||
const handleRemoveLineItem = () => {
|
||||
removeLineItem.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/order-edits/${orderEditId}/items/${itemId}`, {
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X DELETE '<BACKEND_URL>/admin/order-edits/<ORDER_EDIT_ID>/items/<ITEM_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request requires the order edit’s ID and the ID of the item in the original order as path parameters.
|
||||
|
||||
This request returns the Order Edit object. You can access returned item changes using `order_edit.changes`.
|
||||
|
||||
---
|
||||
|
||||
## Revert an Item Change
|
||||
|
||||
A merchant might make a mistake while making a change to the original order’s items. Using the Admin API, you can revert item changes previously created.
|
||||
|
||||
To revert an item change, send a request to the [Delete Item Change](https://docs.medusajs.com/api/admin#order-edits_deleteordereditsorderedititemchange) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orderEdits.deleteItemChange(orderEditId, changeId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDeleteOrderEditItemChange } from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const deleteItemChange = useAdminDeleteOrderEditItemChange(
|
||||
orderEditId,
|
||||
itemChangeId
|
||||
)
|
||||
|
||||
const handleDeleteItemChange = () => {
|
||||
deleteItemChange.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(
|
||||
`<BACKEND_URL>/admin/order-edits/${orderEditId}/changes/${changeId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id, object, deleted)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X DELETE '<BACKEND_URL>/admin/order-edits/<ORDER_EDIT_ID>/changes/<CHANGE_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request requires the order edit’s ID and the item change’s ID as path parameters.
|
||||
|
||||
This request returns an object with the following properties:
|
||||
|
||||
- `id`: The ID of the deleted object. In this case, it’s the ID of the item change.
|
||||
- `object`: A string indicating the type of deleted object. In this case, it’s `item_change`.
|
||||
- `deleted`: A boolean value indicating whether the item change was deleted.
|
||||
|
||||
---
|
||||
|
||||
## Move into Request State
|
||||
|
||||
After an Order Edit is created and all the item changes are added, it must be moved into the request state.
|
||||
|
||||
To move an Order Edit into the request state, send a request to the [Request Confirmation](https://docs.medusajs.com/api/admin#order-edits_postordereditsordereditrequest) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orderEdits.requestConfirmation(orderEditId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(
|
||||
order_edit.requested_at,
|
||||
order_edit.requested_by
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import {
|
||||
useAdminRequestOrderEditConfirmation,
|
||||
} from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const requestOrderConfirmation =
|
||||
useAdminRequestOrderEditConfirmation(
|
||||
orderEditId
|
||||
)
|
||||
|
||||
const handleRequestConfirmation = () => {
|
||||
requestOrderConfirmation.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/order-edits/${orderEditId}/request`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.requested_at, order_edit.requested_by)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/order-edits/<ORDER_EDIT_ID>/request' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request requires the order edit’s ID as a path parameter.
|
||||
|
||||
It returns the Order Edit object. You can access the following properties related to the confirmation request:
|
||||
|
||||
- `requested_at`: A timestamp indicating when the request confirmation was created.
|
||||
- `requested_by`: The ID of the user that requested this order edit.
|
||||
|
||||
:::tip
|
||||
|
||||
This request triggers the event `order-edit.requested`. You can use a subscriber to send an email to the customer with a link to view the order edit on the storefront. You can learn more in the [Events reference](../../../development/events/events-list.md).
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Force-Confirm an Order Edit
|
||||
|
||||
There are two ways to confirm an Order Edit:
|
||||
|
||||
1. Using the Storefront API, which would confirm the Order Edit as a customer;
|
||||
2. Or using the Admin API, which would force-confirm the Order Edit as a merchant.
|
||||
|
||||
Once an Order Edit is confirmed, the changes to the items defined in the Order Edit will be reflected on the original order. So, a change in the totals of the original order, such as the subtotal, will be reflected as well.
|
||||
|
||||
This change can lead to either required additional payments from the customer, or a refund to be made to the customer.
|
||||
|
||||
When the merchant force-confirms the order edit, however, it bypasses the payment flow. This means that the admin can’t capture any additional payment.
|
||||
|
||||
This section covers how the Admin API can be used to force-confirm the Order Edit. You can refer to [this documentation to learn how to implement Order Edit confirmation on the storefront](../storefront/handle-order-edits.mdx).
|
||||
|
||||
To confirm an Order Edit, send a request to the [Confirm Order Edit](https://docs.medusajs.com/api/admin#order-edits_postordereditsordereditconfirm) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orderEdits.confirm(orderEditId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.confirmed_at, order_edit.confirmed_by)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminConfirmOrderEdit } from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const confirmOrderEdit = useAdminConfirmOrderEdit(orderEditId)
|
||||
|
||||
const handleConfirmOrderEdit = () => {
|
||||
confirmOrderEdit.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/order-edits/${orderEditId}/confirm`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.confirmed_at, order_edit.confirmed_by)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/order-edits/<ORDER_EDIT_ID>/confirm' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request accepts the order edit ID as a path parameter.
|
||||
|
||||
It returns the Order Edit object. You can access the following properties related to the order edit confirmation:
|
||||
|
||||
- `confirmed_at`: A timestamp indicating when the order edit was confirmed.
|
||||
- `confirmed_by`: The ID of the user that confirmed the order edit.
|
||||
|
||||
---
|
||||
|
||||
## Receive Additional Payment
|
||||
|
||||
When the total after the order edit is greater than the total of the original order, the merchant can capture the difference from the customer.
|
||||
|
||||
For order edits that are confirmed by the customer, the customer authorizes the payment before confirming it. So, the merchant can capture the payment.
|
||||
|
||||
For force-confirmed order edits, as the customer didn’t authorize the payment, the merchant can’t capture the payment. It has to be handled manually by the merchant.
|
||||
|
||||
:::info
|
||||
|
||||
You can learn how to allow customers to authorize payment on the storefront in [this documentation](../storefront/handle-order-edits.mdx).
|
||||
|
||||
:::
|
||||
|
||||
### Capture Payment
|
||||
|
||||
If the payment is authorized by the customer, it can be captured by sending a request to the [Capture Payment](https://docs.medusajs.com/api/admin#payments_postpaymentspaymentcapture) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.payments.capturePayment(paymentId)
|
||||
.then(({ payment }) => {
|
||||
console.log(payment.captured_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminPaymentsCapturePayment } from "medusa-react"
|
||||
|
||||
const OrderEditPayment = () => {
|
||||
const capturePayment = useAdminPaymentsCapturePayment(
|
||||
paymentId
|
||||
)
|
||||
|
||||
const handleCapturePayment = () => {
|
||||
capturePayment.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEditPayment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/payments/${paymentId}/capture`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ payment }) => {
|
||||
console.log(payment.captured_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/payments/<PAYMENT_ID>/capture' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request requires the ID of the payment as a path parameter. The payment can be retrieved from the order by accessing the array property `order.payments`.
|
||||
|
||||
It returns in the response the full Payment object.
|
||||
|
||||
## Refund Payment
|
||||
|
||||
When the total after the order edit is less than the original order total, the merchant can refund the difference to the customer.
|
||||
|
||||
To refund the difference to the customer, send a request to the [Refund Payment](https://docs.medusajs.com/api/admin#payments_postpaymentspaymentrefunds) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
import { RefundReason } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
medusa.admin.payments.refundPayment(paymentId, {
|
||||
amount,
|
||||
reason: RefundReason.DISCOUNT, // for example
|
||||
})
|
||||
.then(({ refund }) => {
|
||||
console.log(refund.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminPaymentsRefundPayment } from "medusa-react"
|
||||
import { RefundReason } from "@medusajs/medusa"
|
||||
|
||||
const OrderEditPayment = () => {
|
||||
const refundPayment = useAdminPaymentsRefundPayment(paymentId)
|
||||
|
||||
const handleRefundPayment =
|
||||
(amount: number, reason: RefundReason) => {
|
||||
refundPayment.mutate({
|
||||
amount,
|
||||
reason,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEditPayment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/payments/${paymentId}/refund`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
amount,
|
||||
reason: "discount",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ refund }) => {
|
||||
console.log(refund.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/payments/<PAYMENT_ID>/refund' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"amount": 1000,
|
||||
"reason": "discount"
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request requires the ID of the payment as a path parameter. The payment can be retrieved from the order by accessing the array property `order.payments`.
|
||||
|
||||
In the request’s body parameters, the `amount` field parameter is required. It is the amount to be refunded.
|
||||
|
||||
The `reason` request body parameter is also required. Its value is a string that can be one of the following:
|
||||
|
||||
- `discount`
|
||||
- `return`
|
||||
- `swap`
|
||||
- `claim`
|
||||
- `other`
|
||||
|
||||
:::note
|
||||
|
||||
Check out what other parameters can be sent in the [API reference](https://docs.medusajs.com/api/admin#payments_postpaymentspaymentrefunds).
|
||||
|
||||
:::
|
||||
|
||||
It returns in the response the full Refund object.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Handle order edits on the storefront](../storefront/handle-order-edits.mdx)
|
||||
663
www/apps/docs/content/modules/orders/admin/manage-claims.mdx
Normal file
663
www/apps/docs/content/modules/orders/admin/manage-claims.mdx
Normal file
@@ -0,0 +1,663 @@
|
||||
---
|
||||
description: "Learn how to manage claims using the admin REST APIs. This guide includes how to view an order's claims, "
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Manage Claims
|
||||
|
||||
In this document, you’ll learn how to manage claims using the admin REST APIs.
|
||||
|
||||
## Overview
|
||||
|
||||
Using Medusa’s claim admin REST APIs, you can manage claims and perform related admin functionalities.
|
||||
|
||||
### Scenario
|
||||
|
||||
You want to add or use the following admin functionalities:
|
||||
|
||||
- View an order’s claims
|
||||
- Manage claims, including creating, updating, and canceling claims.
|
||||
- Manage a claim’s fulfillment, including creating a fulfillment, creating a shipment, and canceling a fulfillment.
|
||||
|
||||
:::note
|
||||
|
||||
You can learn about managing returns part of a claim in the [Manage Returns documentation](./manage-returns.mdx).
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client](../../../js-client/overview.md) installed and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
### Authenticated Admin User
|
||||
|
||||
You must be an authenticated admin user before following along with the steps in the tutorial.
|
||||
|
||||
You can learn more about [authenticating as an admin user in the API reference](https://docs.medusajs.com/api/admin#authentication).
|
||||
|
||||
---
|
||||
|
||||
## View Order’s Claims
|
||||
|
||||
To view an order’s claims, you can retrieve the order using the [Get Order endpoint](https://docs.medusajs.com/api/admin#orders_getordersorder) and access the order’s claims:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.retrieve(orderId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminOrder } from "medusa-react"
|
||||
|
||||
const Order = () => {
|
||||
const {
|
||||
order,
|
||||
isLoading,
|
||||
} = useAdminOrder(orderId)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{order && (
|
||||
<>
|
||||
<span>{order.display_id}</span>
|
||||
{order.claims?.length > 0 && (
|
||||
<ul>
|
||||
{order.claims.map((claim) => (
|
||||
<li key={claim.id}>{claim.id}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Order
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X GET '<BACKEND_URL>/admin/orders/<ORDER_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request requires the order’s ID as a path parameter.
|
||||
|
||||
The request returns the order as an object. In that object, you can access an array of claim objects using the property `claims` of the order object.
|
||||
|
||||
---
|
||||
|
||||
## Create Claim
|
||||
|
||||
You can create a claim by sending a request to the [Create Claim endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderclaims):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.createClaim(orderId, {
|
||||
type: "refund",
|
||||
claim_items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCreateClaim } from "medusa-react"
|
||||
|
||||
const CreateClaim = () => {
|
||||
const createClaim = useAdminCreateClaim(orderId)
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
createClaim.mutate({
|
||||
type: "refund",
|
||||
claim_items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CreateClaim
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/claims`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: "refund",
|
||||
claim_items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/claims' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"type": "refund",
|
||||
"claim_items": [
|
||||
{
|
||||
"item_id": "<ITEM_ID>",
|
||||
"quantity": 1
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order ID to be passed as a path parameter.
|
||||
|
||||
In the request body, the following parameters are required:
|
||||
|
||||
- `type`: a string indicating the type of claim to be created. Its value can either be `replace` or `refund`. If the type is `replace`, you can pass the `additional_items` parameter with an array of new items to send to the customer. If the type is `refund`, you can pass the `refund_amount` parameter if you want to specify a custom refund amount.
|
||||
- `claim_items`: an array of objects, each object being the item in the order that the claim is being created for. In the object, you must pass the following properties:
|
||||
- `item_id`: a string indicating the ID of the line item in the order.
|
||||
- `quantity`: a number indicating the quantity of the claim.
|
||||
|
||||
There are other optional parameters that you can pass. You can also pass a return reason for each of the claim items. You can learn about the optional request body parameters in the [API reference](https://docs.medusajs.com/api/admin#orders_postordersorderclaims).
|
||||
|
||||
:::note
|
||||
|
||||
Learn how to manage return reasons in [this documentation](./manage-returns.mdx#manage-return-reasons).
|
||||
|
||||
:::
|
||||
|
||||
The request returns the updated order as an object. You can access the order’s claims using the `claims` property of the order object. The value of the `claims` property is an array of claim objects.
|
||||
|
||||
---
|
||||
|
||||
## Update a Claim
|
||||
|
||||
You can update a claim by sending a request to the [Update Claim endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderclaimsclaim):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.updateClaim(orderId, claimId, {
|
||||
no_notification: true,
|
||||
})
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminUpdateClaim } from "medusa-react"
|
||||
|
||||
const UpdateClaim = () => {
|
||||
const updateClaim = useAdminUpdateClaim(orderId)
|
||||
// ...
|
||||
|
||||
const handleUpdate = () => {
|
||||
updateClaim.mutate({
|
||||
claim_id,
|
||||
no_notification: true,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default UpdateClaim
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(
|
||||
`<BACKEND_URL>/admin/orders/${orderId}/claims/${claimId}`,
|
||||
{
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
no_notification: true,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/claims/<CLAIM_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"no_notification": true
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the ID of the order and the claim to be passed as path parameters.
|
||||
|
||||
In the request body, you can pass any of the claim’s fields that you want to update as parameters. In the example above, the `no_notification` field is updated.
|
||||
|
||||
The request returns the updated order as an object. You can access the order’s claims using the `claims` property of the order object. The value of the `claims` property is an array of claim objects.
|
||||
|
||||
---
|
||||
|
||||
## Manage a Claim’s Fulfillments
|
||||
|
||||
### View Claim’s Fulfillments
|
||||
|
||||
Fulfillments are available on a claim object under the `fulfillments` property, which is an array of fulfillment objects.
|
||||
|
||||
### Create Fulfillment
|
||||
|
||||
You can create a fulfillment for a claim by sending a request to the [Create Claim Fulfillment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderclaimsclaimfulfillments):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.fulfillClaim(orderId, claimId, {
|
||||
})
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminFulfillClaim } from "medusa-react"
|
||||
|
||||
const FulfillClaim = () => {
|
||||
const fulfillClaim = useAdminFulfillClaim(orderId)
|
||||
// ...
|
||||
|
||||
const handleFulfill = () => {
|
||||
fulfillClaim.mutate({
|
||||
claim_id,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default FulfillClaim
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/claims/${claimId}/fulfillments`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/claims/<CLAIM_ID>/fulfillments' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order and claim IDs as path parameters.
|
||||
|
||||
In the request body, you can pass optional parameters such as `metadata` or `no_notification`. These parameters will be used to create the fulfillment. You can learn more about available request body parameters in the [API reference](https://docs.medusajs.com/api/admin#orders_postordersorderclaimsclaimfulfillments).
|
||||
|
||||
The request returns the updated order as an object. You can access the order’s claims using the `claims` property of the order object. The value of the `claims` property is an array of claim objects.
|
||||
|
||||
### Create a Shipment
|
||||
|
||||
You can create a shipment for a claim by sending a request to the [Create Claim Shipment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderclaimsclaimshipments):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.createClaimShipment(orderId, claimId, {
|
||||
fulfillment_id,
|
||||
})
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCreateClaimShipment } from "medusa-react"
|
||||
|
||||
const CreateShipment = () => {
|
||||
const createShipment = useAdminCreateClaimShipment(orderId)
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
createShipment.mutate({
|
||||
claim_id,
|
||||
fulfillment_id,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CreateShipment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/claims/${claimId}/shipments`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
fulfillment_id,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/claims/<CLAIM_ID>/shipments' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"fulfillment_id": "<FUL_ID>"
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order and claim IDs as path parameters.
|
||||
|
||||
In the request body, it’s required to pass the `fulfillment_id` parameter, which is the ID of the fulfillment the shipment is being created for. You can pass other optional parameters, such as an array of tracking numbers. You can learn more in the [API reference](https://docs.medusajs.com/api/admin#orders_postordersorderclaimsclaimshipments).
|
||||
|
||||
The request returns the updated order as an object. As mentioned before, a claim’s fulfillments can be accessed using the `fulfillments` property of a claim object. You can access the shipments, known as tracking links, of a fulfillment using the `tracking_links` property of a fulfillment object. The value of `tracking_links` is an array of tracking link objects.
|
||||
|
||||
You can alternatively access the tracking numbers using the `tracking_numbers` property of a fulfillment object, which is an array of strings.
|
||||
|
||||
You can access the status of a claim’s fulfillment using the `fulfillment_status` property of a claim object.
|
||||
|
||||
### Cancel Fulfillment
|
||||
|
||||
:::note
|
||||
|
||||
You can’t cancel a fulfillment that has a shipment
|
||||
|
||||
:::
|
||||
|
||||
You can cancel a fulfillment by sending a request to the [Cancel Fulfillment endpoint](https://docs.medusajs.com/api/admin#orders_postordersclaimfulfillmentscancel):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.cancelClaimFulfillment(
|
||||
orderId,
|
||||
claimId,
|
||||
fulfillmentId
|
||||
)
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCancelClaimFulfillment } from "medusa-react"
|
||||
|
||||
const CancelFulfillment = () => {
|
||||
const cancelFulfillment = useAdminCancelClaimFulfillment(
|
||||
orderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleCancel = () => {
|
||||
cancelFulfillment.mutate({
|
||||
claim_id,
|
||||
fulfillment_id,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CancelFulfillment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/claims/${claimId}/fulfillments/${fulfillmentId}/cancel`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/claims/<CLAIM_ID>/fulfillments/<FUL_ID>/cancel' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order, claim, and fulfillment IDs to be passed as path parameters.
|
||||
|
||||
The request returns the updated order as an object. You can access the claims using the `claims` property of the order object, which is an array of claim objects.
|
||||
|
||||
You can check the fulfillment status of a claim using the `fulfillment_status` property of the claim object.
|
||||
|
||||
---
|
||||
|
||||
## Cancel Claim
|
||||
|
||||
:::note
|
||||
|
||||
You can’t cancel a claim that has been refunded. You must also cancel the claim’s fulfillments and return first.
|
||||
|
||||
:::
|
||||
|
||||
You can cancel a claim by sending a request to the [Cancel Claim endpoint](https://docs.medusajs.com/api/admin#orders_postordersclaimcancel):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.cancelClaim(orderId, claimId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCancelClaim } from "medusa-react"
|
||||
|
||||
const CancelClaim = () => {
|
||||
const cancelClaim = useAdminCancelClaim(orderId)
|
||||
// ...
|
||||
|
||||
const handleCancel = () => {
|
||||
cancelClaim.mutate(claimId)
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CancelClaim
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/claims/${claimId}/cancel`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.claims)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/claims/<CLAIM_ID>/cancel' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order and claim IDs as path parameters.
|
||||
|
||||
The request returns the updated order as an object. You can access the claims using the `claims` property of the order object, which is an array of claim objects.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage returns](./manage-returns.mdx)
|
||||
- [How to manage orders](./manage-orders.mdx)
|
||||
@@ -0,0 +1,838 @@
|
||||
---
|
||||
description: 'Learn how to manage draft orders using the admin REST APIs. This guide includes how to manage draft orders including listing and creating them, manage their line items, and register their payment.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Manage Draft Orders
|
||||
|
||||
In this document, you’ll learn how to manage draft orders using the admin REST APIs.
|
||||
|
||||
## Overview
|
||||
|
||||
Using the draft orders admin REST APIs, you can manage draft orders and perform other related functionalities.
|
||||
|
||||
### Scenario
|
||||
|
||||
You want to add or use the following admin functionalities:
|
||||
|
||||
- Manage draft orders, including listing, creating, updating, and deleting draft orders.
|
||||
- Managing line items in draft orders, including adding, updating, and deleting items from a draft order.
|
||||
- Authorize and capture a draft order’s payment.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client](../../../js-client/overview.md) installed and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
### Authenticated Admin User
|
||||
|
||||
You must be an authenticated admin user before following along with the steps in the tutorial.
|
||||
|
||||
You can learn more about [authenticating as an admin user in the API reference](https://docs.medusajs.com/api/admin#authentication).
|
||||
|
||||
---
|
||||
|
||||
## List Draft Orders
|
||||
|
||||
You can list draft orders by sending a request to the [List Draft Orders endpoint](https://docs.medusajs.com/api/admin#draft-orders_getdraftorders):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.draftOrders.list()
|
||||
.then(({ draft_orders, limit, offset, count }) => {
|
||||
console.log(draft_orders.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDraftOrders } from "medusa-react"
|
||||
|
||||
const DraftOrders = () => {
|
||||
const { draft_orders, isLoading } = useAdminDraftOrders()
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{draft_orders && !draft_orders.length && (
|
||||
<span>No Draft Orders</span>
|
||||
)}
|
||||
{draft_orders && draft_orders.length > 0 && (
|
||||
<ul>
|
||||
{draft_orders.map((order) => (
|
||||
<li key={order.id}>{order.display_id}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DraftOrders
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/draft-orders`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ draft_orders, limit, offset, count }) => {
|
||||
console.log(draft_orders.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X GET '<BACKEND_URL>/admin/draft-orders' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint does not require any path or query parameters. You can pass search or pagination query parameters as explained in the [API reference](https://docs.medusajs.com/api/admin#draft-orders_getdraftorders).
|
||||
|
||||
The request returns an array of draft order objects along with [pagination parameters](https://docs.medusajs.com/api/admin#pagination).
|
||||
|
||||
---
|
||||
|
||||
## Create a Draft Order
|
||||
|
||||
You can create a draft order by sending a request to the [Create Draft Order endpoint](https://docs.medusajs.com/api/admin#draft-orders_postdraftorders):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.draftOrders.create({
|
||||
email,
|
||||
region_id,
|
||||
items: [
|
||||
{
|
||||
// defined product
|
||||
quantity: 1,
|
||||
variant_id,
|
||||
},
|
||||
{
|
||||
// custom product
|
||||
quantity: 1,
|
||||
unit_price: 1000,
|
||||
title: "Custom Product",
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
option_id,
|
||||
// for custom shipping price
|
||||
price,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCreateDraftOrder } from "medusa-react"
|
||||
|
||||
const CreateDraftOrder = () => {
|
||||
const createDraftOrder = useAdminCreateDraftOrder()
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
createDraftOrder.mutate({
|
||||
email,
|
||||
region_id,
|
||||
items: [
|
||||
{
|
||||
// defined product
|
||||
quantity: 1,
|
||||
variant_id,
|
||||
},
|
||||
{
|
||||
// custom product
|
||||
quantity: 1,
|
||||
unit_price: 1000,
|
||||
title: "Custom Product",
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
option_id,
|
||||
// for custom shipping price
|
||||
price,
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CreateDraftOrder
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/draft-orders`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
region_id,
|
||||
items: [
|
||||
{
|
||||
// defined product
|
||||
quantity: 1,
|
||||
variant_id,
|
||||
},
|
||||
{
|
||||
// custom product
|
||||
quantity: 1,
|
||||
unit_price: 1000,
|
||||
title: "Custom Product",
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
option_id,
|
||||
// for custom shipping price
|
||||
price,
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/draft-orders' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"email": "<EMAIL>",
|
||||
"region_id": "<REGION_ID>",
|
||||
"items": [
|
||||
{
|
||||
"quantity": 1,
|
||||
"variant_id": "<VARIANT_ID>"
|
||||
},
|
||||
{
|
||||
"quantity": 1,
|
||||
"unit_price": 1000,
|
||||
"title": "Custom Product"
|
||||
}
|
||||
],
|
||||
"shipping_methods": [
|
||||
{
|
||||
"option_id": "<OPTION_ID>",
|
||||
"price": 1000
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the following request body parameters:
|
||||
|
||||
- `email`: a string indicating the email of the customer to associate this draft order with.
|
||||
- `region_id`: a string indicating the ID of the region this draft order belongs to.
|
||||
- `shipping_methods`: an array of objects, each object being a shipping method to use for the draft order. The object is required to have the `option_id` property which is the ID of the shipping option to use. You can optionally specify a `price` property to set a custom amount for the price.
|
||||
|
||||
You can also pass other optional parameters. For example, the `items` array can be passed to add line items to the draft order. There are two types of items that you can add:
|
||||
|
||||
1. Defined product variants. This is done by passing the `variant_id` property, with its value being the ID of the product variant to add.
|
||||
2. Custom products that aren’t defined in your store. This is done by passing the `unit_price` property with its value being the price of the custom product, and the `title` property with its value being the title of the custom product.
|
||||
|
||||
You must also pass for each item its quantity.
|
||||
|
||||
To learn about other optional request body parameters, such as passing shipping or billing addresses, check out the [API reference](https://docs.medusajs.com/api/admin#draft-orders_postdraftorders).
|
||||
|
||||
The request returns the created draft order as an object.
|
||||
|
||||
---
|
||||
|
||||
## Retrieve Draft Order
|
||||
|
||||
You can retrieve a draft order by sending a request to the [Get Draft Order endpoint](https://docs.medusajs.com/api/admin#draft-orders_getdraftordersdraftorder):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.draftOrders.retrieve(draftOrderId)
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDraftOrder } from "medusa-react"
|
||||
|
||||
const DraftOrder = () => {
|
||||
const {
|
||||
draft_order,
|
||||
isLoading,
|
||||
} = useAdminDraftOrder(draftOrderId)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{draft_order && <span>{draft_order.display_id}</span>}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DraftOrder
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X GET '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the draft order’s ID as a path parameter.
|
||||
|
||||
The request returns the draft order as an object.
|
||||
|
||||
---
|
||||
|
||||
## Update Draft Order
|
||||
|
||||
You can update a draft order by sending a request to the [Update Draft Order endpoint](https://docs.medusajs.com/api/admin#draft-orders_postdraftordersdraftorder):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.draftOrders.update(draftOrderId, {
|
||||
email: "user@example.com",
|
||||
})
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminUpdateDraftOrder } from "medusa-react"
|
||||
|
||||
const UpdateDraftOrder = () => {
|
||||
const updateDraftOrder = useAdminUpdateDraftOrder(
|
||||
draftOrderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleUpdate = () => {
|
||||
updateDraftOrder.mutate({
|
||||
email: "user@example.com",
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default UpdateDraftOrder
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: "user@example.com",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"email": "user@example.com"
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the draft order’s ID as a path parameter.
|
||||
|
||||
In the request body, you can pass any of the draft order’s fields to update. In the example above, you update the `email` field. Check out the [API reference](https://docs.medusajs.com/api/admin#draft-orders_postdraftordersdraftorder) to learn about other accepted request body parameters.
|
||||
|
||||
The request returns the updated draft order as an object.
|
||||
|
||||
---
|
||||
|
||||
## Manage Line Items
|
||||
|
||||
### Add Line Items
|
||||
|
||||
You can add line items to a draft order by sending a request to the [Create Line Items endpoint](https://docs.medusajs.com/api/admin#draft-orders_postdraftordersdraftorderlineitems):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.draftOrders.addLineItem(draftOrderId, {
|
||||
quantity: 1,
|
||||
})
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.cart.items)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDraftOrderAddLineItem } from "medusa-react"
|
||||
|
||||
const AddLineItem = () => {
|
||||
const addLineItem = useAdminDraftOrderAddLineItem(
|
||||
draftOrderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleAdd = () => {
|
||||
addLineItem.mutate({
|
||||
quantity: 1,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default AddLineItem
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}/line-items`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
quantity: 1,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.cart.items)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>/line-items' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"quantity": 1
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the ID of the draft order as a path parameter.
|
||||
|
||||
In the request body, it’s required to pass the `quantity` parameter, which is a number indicating the quantity of the item in the draft order. You can also pass other optional parameters based on the type of line item you’re adding.
|
||||
|
||||
There are two types of items that you can add:
|
||||
|
||||
1. Defined product variants. This is done by passing the `variant_id` parameter, with its value being the ID of the product variant to add.
|
||||
2. Custom products that aren’t defined in your store. This is done by passing the `unit_price` parameter with its value being the price of the custom product, and the `title` property with its value being the title of the custom product.
|
||||
|
||||
Check the [API reference](https://docs.medusajs.com/api/admin#draft-orders_postdraftordersdraftorderlineitems) for a full list of request body parameters.
|
||||
|
||||
The request returns the updated draft order as an object. You can access the draft order’s items by accessing the `carts` property in the draft item, then the `items` property. The `items` property is an array of line item objects.
|
||||
|
||||
### Update Line Item
|
||||
|
||||
You can update a line item by sending a request to the [Update Line Item endpoint](https://docs.medusajs.com/api/admin#draft-orders_postdraftordersdraftorderlineitemsitem):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.draftOrders.updateLineItem(draftOrderId, itemId, {
|
||||
quantity: 1,
|
||||
})
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.cart.items)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDraftOrderUpdateLineItem } from "medusa-react"
|
||||
|
||||
const UpdateLineItem = () => {
|
||||
const updateLineItem = useAdminDraftOrderUpdateLineItem(
|
||||
draftOrderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleUpdate = () => {
|
||||
updateLineItem.mutate({
|
||||
item_id,
|
||||
quantity: 1,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default UpdateLineItem
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}/line-items/${itemId}`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
quantity: 1,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.cart.items)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>/line-items/<ITEM_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"quantity": 1
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the draft order and line item’s IDs as path parameters.
|
||||
|
||||
In the request body, you can pass any of the line item’s fields as parameters to update them. In the example above, you pass the `quantity` parameter to update the quantity of the item. Check out the [API reference](https://docs.medusajs.com/api/admin#draft-orders_postdraftordersdraftorderlineitemsitem) for a full list of request body parameters.
|
||||
|
||||
The request returns the updated draft order as an object. You can access the draft order’s items by accessing the `carts` property in the draft item, then the `items` property. The `items` property is an array of line item objects.
|
||||
|
||||
### Delete Line Item
|
||||
|
||||
You can delete a line item by sending a request to the [Delete Line Item endpoint](https://docs.medusajs.com/api/admin#draft-orders_deletedraftordersdraftorderlineitemsitem):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.draftOrders.removeLineItem(draftOrderId, itemId)
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.cart.items)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDraftOrderRemoveLineItem } from "medusa-react"
|
||||
|
||||
const DeleteLineItem = () => {
|
||||
const deleteLineItem = useAdminDraftOrderRemoveLineItem(
|
||||
draftOrderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleDelete = () => {
|
||||
deleteLineItem.mutate(itemId)
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default DeleteLineItem
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}/line-items/${itemId}`, {
|
||||
credentials: "include",
|
||||
method: "DELETE",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ draft_order }) => {
|
||||
console.log(draft_order.cart.items)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X DELETE '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>/line-items/<ITEM_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the draft order and line item’s IDs as path parameters.
|
||||
|
||||
The request returns the updated draft order as an object. You can access the draft order’s items by accessing the `carts` property in the draft item, then the `items` property. The `items` property is an array of line item objects.
|
||||
|
||||
---
|
||||
|
||||
## Register Draft Order Payment
|
||||
|
||||
Registering the draft order’s payment leads to authorizing and capturing the payment using the `system` payment method. This would complete the draft order and create an order from it.
|
||||
|
||||
You can register the draft order payment by sending a request to the [Register Draft Order Payment endpoint](https://docs.medusajs.com/api/admin#draft-orders_postdraftordersdraftorderregisterpayment):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.draftOrders.markPaid(draftOrderId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDraftOrderRegisterPayment } from "medusa-react"
|
||||
|
||||
const RegisterPayment = () => {
|
||||
const registerPayment = useAdminDraftOrderRegisterPayment(
|
||||
draftOrderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handlePayment = () => {
|
||||
registerPayment.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default RegisterPayment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}/pay`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>/pay' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the draft order’s ID as a path parameter.
|
||||
|
||||
The request returns the order created from the draft order as an object.
|
||||
|
||||
---
|
||||
|
||||
## Delete a Draft Order
|
||||
|
||||
You can delete a draft order by sending a request to the [Delete Draft Order endpoint](https://docs.medusajs.com/api/admin#draft-orders_deletedraftordersdraftorder):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.draftOrders.delete(draftOrderId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDeleteDraftOrder } from "medusa-react"
|
||||
|
||||
const DeleteDraftOrder = () => {
|
||||
const deleteDraftOrder = useAdminDeleteDraftOrder(
|
||||
draftOrderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleDelete = () => {
|
||||
deleteDraftOrder.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default DeleteDraftOrder
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/draft-orders/${draftOrderId}`, {
|
||||
credentials: "include",
|
||||
method: "DELETE",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X DELETE '<BACKEND_URL>/admin/draft-orders/<DRAFT_ORDER_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the draft order’s ID as a path parameter.
|
||||
|
||||
The request returns the following fields:
|
||||
|
||||
- `id`: The ID of the deleted draft order.
|
||||
- `object`: The type of object that was deleted. In this case, the value will be `draft-order`.
|
||||
- `deleted`: A boolean value indicating whether the draft order was deleted.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage orders](./manage-orders.mdx)
|
||||
- [Orders architecture overview](../orders.md)
|
||||
1171
www/apps/docs/content/modules/orders/admin/manage-orders.mdx
Normal file
1171
www/apps/docs/content/modules/orders/admin/manage-orders.mdx
Normal file
File diff suppressed because it is too large
Load Diff
652
www/apps/docs/content/modules/orders/admin/manage-returns.mdx
Normal file
652
www/apps/docs/content/modules/orders/admin/manage-returns.mdx
Normal file
@@ -0,0 +1,652 @@
|
||||
---
|
||||
description: "Learn how to manage returns using the admin REST APIs. This guide includes how to manage return reasons, view returns, mark a return as received, and cancel a return."
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Manage Returns
|
||||
|
||||
In this document, you’ll learn how to manage returns using the admin REST APIs.
|
||||
|
||||
## Overview
|
||||
|
||||
Using the returns, orders, and return reasons admin REST APIs, you can manage returns and perform other related functionalities.
|
||||
|
||||
### Scenario
|
||||
|
||||
You want to add or use the following admin functionalities:
|
||||
|
||||
- Manage Return Reasons. This includes listing return reasons, creating, updating, and deleting them.
|
||||
- View an Order’s, Swap’s, and Claim’s Returns
|
||||
- Mark a Return Received
|
||||
- Cancel a Return
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client](../../../js-client/overview.md) installed and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
### Authenticated Admin User
|
||||
|
||||
You must be an authenticated admin user before following along with the steps in the tutorial.
|
||||
|
||||
You can learn more about [authenticating as an admin user in the API reference](https://docs.medusajs.com/api/admin#authentication).
|
||||
|
||||
---
|
||||
|
||||
## Manage Return Reasons
|
||||
|
||||
Return reasons allow you to specify why an item is returned. They are especially useful for claims, but you can also use them to ask customers to specify the reason they’re requesting to return an item.
|
||||
|
||||
### List Return Reasons
|
||||
|
||||
You can list available return reasons using the [List Return Reasons endpoint](https://docs.medusajs.com/api/admin#return-reasons_getreturnreasons):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.returnReasons.list()
|
||||
.then(({ return_reasons }) => {
|
||||
console.log(return_reasons.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminReturnReasons } from "medusa-react"
|
||||
|
||||
const ReturnReasons = () => {
|
||||
const { return_reasons, isLoading } = useAdminReturnReasons()
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{return_reasons && !return_reasons.length && (
|
||||
<span>No Return Reasons</span>
|
||||
)}
|
||||
{return_reasons && return_reasons.length > 0 && (
|
||||
<ul>
|
||||
{return_reasons.map((reason) => (
|
||||
<li key={reason.id}>
|
||||
{reason.label}: {reason.value}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReturnReasons
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/return-reasons`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ return_reasons }) => {
|
||||
console.log(return_reasons.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X GET '<BACKEND_URL>/admin/return-reasons' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint does not require or accept any path or query parameters.
|
||||
|
||||
The request returns an array of return reason objects.
|
||||
|
||||
### Create a Return Reason
|
||||
|
||||
You can create a return reason using the [Create Return Reason endpoint](https://docs.medusajs.com/api/admin#return-reasons_postreturnreasons):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.returnReasons.create({
|
||||
label: "Damaged",
|
||||
value: "damaged",
|
||||
})
|
||||
.then(({ return_reason }) => {
|
||||
console.log(return_reason.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCreateReturnReason } from "medusa-react"
|
||||
|
||||
const CreateReturnReason = () => {
|
||||
const createReturnReason = useAdminCreateReturnReason()
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
createReturnReason.mutate({
|
||||
label: "Damaged",
|
||||
value: "damaged",
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CreateReturnReason
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/return-reasons`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
label: "Damaged",
|
||||
value: "damaged",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ return_reason }) => {
|
||||
console.log(return_reason.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/return-reasons' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"label": "Damaged",
|
||||
"value": "damaged"
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the following request body parameters:
|
||||
|
||||
- `label`: a string that will be used as the label of the return reason. This is typically the label shown to the customer or the merchant.
|
||||
- `value`: a string that is unique among return reasons. It is typically used internally for identification
|
||||
|
||||
You can also pass other optional request body parameters, such as a `description` parameter or a `parent_return_reason_id` if this return reason is a child of another. You can learn more about available optional request body parameters in the [API reference](https://docs.medusajs.com/api/admin#return-reasons_postreturnreasons).
|
||||
|
||||
This request returns the created return reason as an object.
|
||||
|
||||
### Update a Return Reason
|
||||
|
||||
You can update a return reason by sending a request to the [Update Return Reason endpoint](https://docs.medusajs.com/api/admin#return-reasons_postreturnreasonsreason):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.returnReasons.update(returnReasonId, {
|
||||
label: "Damaged",
|
||||
})
|
||||
.then(({ return_reason }) => {
|
||||
console.log(return_reason.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminUpdateReturnReason } from "medusa-react"
|
||||
|
||||
const UpdateReturnReason = () => {
|
||||
const updateReturnReason = useAdminUpdateReturnReason(
|
||||
returnReasonId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleUpdate = () => {
|
||||
updateReturnReason.mutate({
|
||||
label: "Damaged",
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default UpdateReturnReason
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/return-reasons/${returnReasonId}`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
label: "Damaged",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ return_reason }) => {
|
||||
console.log(return_reason.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/return-reasons/<REASON_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"label": "Damaged"
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the return reason ID to be passed as a path parameter.
|
||||
|
||||
In the request body, you can pass any of the return reason’s fields that you want to update as parameters. In the example above, the label is passed in the request body to be updated.
|
||||
|
||||
The request returns the updated return reason as an object.
|
||||
|
||||
### Delete a Return Reason
|
||||
|
||||
You can delete a return reason by sending a request to the [Delete Return Reason endpoint](https://docs.medusajs.com/api/admin#return-reasons_deletereturnreason):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.returnReasons.delete(returnReasonId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDeleteReturnReason } from "medusa-react"
|
||||
|
||||
const DeleteReturnReason = () => {
|
||||
const deleteReturnReason = useAdminDeleteReturnReason(
|
||||
returnReasonId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleDelete = () => {
|
||||
deleteReturnReason.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default DeleteReturnReason
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/return-reasons/${returnReasonId}`, {
|
||||
credentials: "include",
|
||||
method: "DELETE",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X DELETE '<BACKEND_URL>/admin/return-reasons/<REASON_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the return reason ID as a path parameter.
|
||||
|
||||
The request returns the following fields:
|
||||
|
||||
- `id`: The ID of the deleted return reason.
|
||||
- `object`: The type of object that was deleted. In this case, the value will be `return_reason`.
|
||||
- `deleted`: A boolean value indicating whether the return reason was deleted.
|
||||
|
||||
---
|
||||
|
||||
## View an Order’s Returns
|
||||
|
||||
:::note
|
||||
|
||||
You can view all returns in your commerce system, regardless of which order they belong to, using the [List Returns endpoint](https://docs.medusajs.com/api/admin#return-reasons_getreturnreasons).
|
||||
|
||||
:::
|
||||
|
||||
When you retrieve an order using the [Get Order endpoint](https://docs.medusajs.com/api/admin#orders_getordersorder), you can access the returns within the order object:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.retrieve(orderId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.returns)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminOrder } from "medusa-react"
|
||||
|
||||
const Order = () => {
|
||||
const {
|
||||
order,
|
||||
isLoading,
|
||||
} = useAdminOrder(orderId)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{order && (
|
||||
<>
|
||||
<span>{order.display_id}</span>
|
||||
{order.returns?.length > 0 && (
|
||||
<ul>
|
||||
{order.returns.map((orderReturn) => (
|
||||
<li key={orderReturn.id}>{orderReturn.id}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Order
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.returns)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X GET '<BACKEND_URL>/admin/orders/<ORDER_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order ID as a path parameter.
|
||||
|
||||
The request returns the order as an object. In that object, you can access an array of return objects using the property `returns` of the order object.
|
||||
|
||||
---
|
||||
|
||||
## View a Swap’s Return
|
||||
|
||||
You can retrieve a swap either using the Get Order endpoint as explained [here](./manage-swaps.mdx#view-orders-swaps), or using the [List Swaps](https://docs.medusajs.com/api/admin#swaps_getswaps) or [Get Swap endpoint](https://docs.medusajs.com/api/admin#swaps_getswapsswap).
|
||||
|
||||
In a swap object, the swap’s return is available under the `return_order` property.
|
||||
|
||||
---
|
||||
|
||||
## View a Claim’s Return
|
||||
|
||||
You can retrieve a claim using the Get Order endpoint as explained [here](./manage-claims#view-orders-claims). In a claim object, the claim’s return is available under the `return_order` property.
|
||||
|
||||
---
|
||||
|
||||
## Mark a Return as Received
|
||||
|
||||
You can mark a return as received by sending a request to the [Receive a Return endpoint](https://docs.medusajs.com/api/admin#returns_postreturnsreturnreceive):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.returns.receive(return_id, {
|
||||
items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then((data) => {
|
||||
console.log(data.return.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminReceiveReturn } from "medusa-react"
|
||||
|
||||
const ReceiveReturn = () => {
|
||||
const receiveReturn = useAdminReceiveReturn(
|
||||
returnId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleReceive = () => {
|
||||
receiveReturn.mutate({
|
||||
email,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default ReceiveReturn
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/returns/${returnId}/receive`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
console.log(data.return.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/returns/<RETURN_ID>/receive' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"items": [
|
||||
{
|
||||
"item_id": "<ITEM_ID>",
|
||||
"quantity": 1
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the ID of the return as a path parameter.
|
||||
|
||||
In the request body, the `items` parameter is required. It’s an array of objects having the following properties:
|
||||
|
||||
- `item_id`: a string indicating the ID of the line item in the order that is received.
|
||||
- `quantity`: a number indicating the quantity of the line item that was received.
|
||||
|
||||
By default, the refund amount specified in the return will be refunded. If you want to refund a custom amount, you can pass the optional request body parameter `refund`, with its value being a number indicating the amount to refund. The amount must be less than the order’s `refundable_amount`.
|
||||
|
||||
The request returns the updated return as an object.
|
||||
|
||||
---
|
||||
|
||||
## Cancel a Return
|
||||
|
||||
:::note
|
||||
|
||||
A received return can’t be canceled.
|
||||
|
||||
:::
|
||||
|
||||
You can cancel a return by sending a request to the [Cancel Return endpoint](https://docs.medusajs.com/api/admin#returns_postreturnsreturncancel):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.returns.cancel(returnId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.returns)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCancelReturn } from "medusa-react"
|
||||
|
||||
const CancelReturn = () => {
|
||||
const cancelReturn = useAdminCancelReturn(
|
||||
returnId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleCancel = () => {
|
||||
cancelReturn.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CancelReturn
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/returns/${returnId}/cancel`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.returns)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/returns/<RETURN_ID>/cancel' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the return ID to be passed as a path parameter.
|
||||
|
||||
The request returns one of the following object types:
|
||||
|
||||
- If a return belongs to a swap, a swap object is returned. You can access the returns in the `return_order` property of the swap object.
|
||||
- If a return belongs to a claim, a claim object is returned. You can access the returns in the `return_order` property of the claim object.
|
||||
- Otherwise, an order object is returned. You can access the returns in the `returns` property of the order object.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage orders using the REST APIs](./manage-orders.mdx)
|
||||
- [How to manage swaps using the REST APIs](./manage-swaps.mdx)
|
||||
- [How to manage claims using the REST APIs](./manage-claims.mdx)
|
||||
543
www/apps/docs/content/modules/orders/admin/manage-swaps.mdx
Normal file
543
www/apps/docs/content/modules/orders/admin/manage-swaps.mdx
Normal file
@@ -0,0 +1,543 @@
|
||||
---
|
||||
description: "Learn how to manage swaps using the admin REST APIs. This guide includes how to view an order's swaps, manage a swap's payment and fulfillment, and cancel a swap."
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Manage Swaps
|
||||
|
||||
In this document, you’ll learn how to manage swaps using the admin REST APIs.
|
||||
|
||||
## Overview
|
||||
|
||||
Using the order’s admin REST APIs, you can manage and process the swaps of an order in your commerce store.
|
||||
|
||||
### Scenario
|
||||
|
||||
You want to add or use the following admin functionalities:
|
||||
|
||||
- View an order’s swaps.
|
||||
- Process a swap’s payment.
|
||||
- Manage a swap’s fulfillment. This includes creating a fulfillment, creating a shipment, and canceling a fulfillment.
|
||||
- Cancel a swap.
|
||||
|
||||
:::note
|
||||
|
||||
You can learn about managing returns in the [Manage Returns documentation](./manage-returns.mdx).
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client](../../../js-client/overview.md) installed and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
### Authenticated Admin User
|
||||
|
||||
You must be an authenticated admin user before following along with the steps in the tutorial.
|
||||
|
||||
You can learn more about [authenticating as an admin user in the API reference](https://docs.medusajs.com/api/admin#authentication).
|
||||
|
||||
---
|
||||
|
||||
## View Order’s Swaps
|
||||
|
||||
:::note
|
||||
|
||||
If you want to view all swaps in your system, and not swaps specific to an order, you can use the [List Swaps endpoint](https://docs.medusajs.com/api/admin#swaps_getswaps) instead.
|
||||
|
||||
:::
|
||||
|
||||
You can view an order’s swaps by retrieving the order using the [Get Order endpoint](https://docs.medusajs.com/api/admin#orders_getordersorder):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.retrieve(orderId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminOrder } from "medusa-react"
|
||||
|
||||
const Order = () => {
|
||||
const {
|
||||
order,
|
||||
isLoading,
|
||||
} = useAdminOrder(orderId)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{order && (
|
||||
<>
|
||||
<span>{order.display_id}</span>
|
||||
{order.swaps?.length > 0 && (
|
||||
<ul>
|
||||
{order.swaps.map((swap) => (
|
||||
<li key={swap.id}>{swap.difference_due}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Order
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X GET '<BACKEND_URL>/admin/orders/<ORDER_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order ID to be passed as a path parameter.
|
||||
|
||||
The request returns the order as an object. The order’s swaps are available under the `swaps` property, which is an array of swap objects.
|
||||
|
||||
---
|
||||
|
||||
## Process Swap Payment
|
||||
|
||||
Processing a swap’s payment can mean either refunding or capturing payment, depending on the value of `difference_due` of the swap. If the `difference_due` is less than 0, then the payment should be refunded. If it’s greater than 0, then the payment should be captured. If it’s 0, no payment processing is performed.
|
||||
|
||||
Regardless of whether you need to refund or capture the payment, you can process the swap’s payment by sending a request to the [Process Swap Payment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderswapsswapprocesspayment):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.processSwapPayment(orderId, swapId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminProcessSwapPayment } from "medusa-react"
|
||||
|
||||
const ProcessPayment = () => {
|
||||
const processPayment = useAdminProcessSwapPayment(
|
||||
orderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleProcess = () => {
|
||||
processPayment.mutate(swapId)
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default ProcessPayment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/swaps/${swapId}/process-payment`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/swaps/<SWAP_ID>/process-payment' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order ID and the swap ID as path parameters.
|
||||
|
||||
The request returns the updated order as an object. You can access the swaps of the order in the `order.swaps` property. It’s an array of swap objects.
|
||||
|
||||
---
|
||||
|
||||
## Manage a Swap’s Fulfillments
|
||||
|
||||
### View Swap’s Fulfillments
|
||||
|
||||
Fulfillments are available on a swap object under the `fulfillments` property, which is an array of fulfillment objects.
|
||||
|
||||
### Create a Fulfillment
|
||||
|
||||
You can create a fulfillment for a swap by sending a request to the [Create Swap Fulfillment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderswapsswapfulfillments):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.fulfillSwap(orderId, swapId, {
|
||||
})
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminFulfillSwap } from "medusa-react"
|
||||
|
||||
const FulfillSwap = () => {
|
||||
const fulfillSwap = useAdminFulfillSwap(
|
||||
orderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleFulfill = () => {
|
||||
fulfillSwap.mutate({
|
||||
swap_id: swapId,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default FulfillSwap
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/swaps/${swapId}/fulfillments`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/swaps/<SWAP_ID>/fulfillments' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order ID and swap ID as path parameters.
|
||||
|
||||
In the request body, you can pass optional parameters such as `metadata` or `no_notification`. These parameters will be used to create the fulfillment. You can learn more about available request body parameters in the [API reference](https://docs.medusajs.com/api/admin#orders_postordersorderswapsswapfulfillments).
|
||||
|
||||
The request returns the updated order as an object. You can access the order’s swaps in the `swaps` property, which is an array of swap objects.
|
||||
|
||||
### Create a Shipment
|
||||
|
||||
You can create a shipment for a swap’s fulfillment using the [Create Swap Shipment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderswapsswapshipments):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.createSwapShipment(orderId, swapId, {
|
||||
fulfillment_id,
|
||||
})
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCreateSwapShipment } from "medusa-react"
|
||||
|
||||
const CreateShipment = () => {
|
||||
const createShipment = useAdminCreateSwapShipment(
|
||||
orderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
createShipment.mutate({
|
||||
swap_id,
|
||||
fulfillment_id,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CreateShipment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/swaps/${swapId}/shipments`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
fulfillment_id,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/swaps/<SWAP_ID>/shipments' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'\
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"fulfillment_id": "<FUL_ID>"
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint expects the order and swap IDs to be passed as path parameters.
|
||||
|
||||
In the request body, it’s required to pass the `fulfillment_id` parameter, which is the ID of the fulfillment the shipment is being created for. You can pass other optional parameters, such as an array of tracking numbers. You can learn more in the [API reference](https://docs.medusajs.com/api/admin#tag/Orders/operation/PostOrdersOrderSwapsSwapShipments).
|
||||
|
||||
The request returns the updated order as an object. As mentioned before, a swap’s fulfillments can be accessed using the `fulfillments` property of a swap object. You can access the shipments, known as tracking links, of a fulfillment using the `tracking_links` property of a fulfillment object. The value of `tracking_links` is an array of tracking link objects.
|
||||
|
||||
You can alternatively access the tracking numbers using the `tracking_numbers` property of a fulfillment object, which is an array of strings.
|
||||
|
||||
You can access the status of a swap’s fulfillment using the `fulfillment_status` property of a swap object.
|
||||
|
||||
### Cancel a Fulfillment
|
||||
|
||||
:::note
|
||||
|
||||
You can’t cancel a fulfillment that has a shipment
|
||||
|
||||
:::
|
||||
|
||||
You can cancel a fulfillment by sending a request to the [Cancel Swap Fulfillment endpoint](https://docs.medusajs.com/api/admin#orders_postordersswapfulfillmentscancel):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.cancelSwapFulfillment(
|
||||
orderId,
|
||||
swapId,
|
||||
fulfillmentId
|
||||
)
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCancelSwapFulfillment } from "medusa-react"
|
||||
|
||||
const CancelFulfillment = () => {
|
||||
const cancelFulfillment = useAdminCancelSwapFulfillment(
|
||||
orderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleCancel = () => {
|
||||
cancelFulfillment.mutate({
|
||||
swap_id,
|
||||
fulfillment_id,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CancelFulfillment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/swaps/${swapId}/shipments/${fulfillmentId}/cancel`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/swaps/<SWAP_ID>/fulfillments/<FUL_ID>/cancel' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order, swap, and fulfillment IDs to be passed as path parameters.
|
||||
|
||||
The request returns the updated order as an object. You can access the swaps using the `swaps` property of the order object, which is an array of swap objects.
|
||||
|
||||
You can check the fulfillment status of a swap using the `fulfillment_status` property of the swap object.
|
||||
|
||||
---
|
||||
|
||||
## Cancel Swap
|
||||
|
||||
:::note
|
||||
|
||||
You can’t cancel a swap that has been refunded. You must also cancel all swap’s fulfillments and return first.
|
||||
|
||||
:::
|
||||
|
||||
You can cancel a swap by sending a request to the [Cancel Swap endpoint](https://docs.medusajs.com/api/admin#orders_postordersswapcancel):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.orders.cancelSwap(orderId, swapId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCancelSwap } from "medusa-react"
|
||||
|
||||
const CancelSwap = () => {
|
||||
const cancelSwap = useAdminCancelSwap(
|
||||
orderId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleCancel = () => {
|
||||
cancelSwap.mutate(swapId)
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CancelSwap
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/orders/${orderId}/swaps/${swapId}/cancel`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.swaps)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/orders/<ORDER_ID>/swaps/<SWAP_ID>/cancel' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order and swap IDs as path parameters.
|
||||
|
||||
The request returns the updated order as an object. You can access the swaps using the `swaps` property of the order object, which is an array of swap objects.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage orders using admin APIs](./manage-orders.mdx)
|
||||
- [How to manage returns using admin APIs](./manage-returns.mdx)
|
||||
@@ -0,0 +1,204 @@
|
||||
---
|
||||
description: 'Learn how to handle the order claim event in the Medusa backend. When the event is triggered, you can send an email to the customer to inform them about it.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
# How to Handle Order Claim Event
|
||||
|
||||
In this document, you’ll learn how to handle the order claim event and send a confirmation email when the event is triggered.
|
||||
|
||||
## Overview
|
||||
|
||||
When a guest customer places an order, the order is not associated with a customer. It is associated with an email address.
|
||||
|
||||
After the customer registers, later on, they can claim that order by providing the order’s ID.
|
||||
|
||||
When the customer requests to claim the order, the event `order-update-token.created` is triggered on the Medusa backend. This event should be used to send the customer a confirmation email.
|
||||
|
||||
### What You’ll Learn
|
||||
|
||||
In this document, you’ll learn how to handle the `order-update-token.created` event on the backend to send the customer a confirmation email.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It's assumed that you already have a Medusa backend installed and set up. If not, you can follow the [quickstart guide](../../../development/backend/install.mdx) to get started. The Medusa backend must also have an event bus module installed, which is available when using the default Medusa backend starter.
|
||||
|
||||
### Notification Provider
|
||||
|
||||
To send an email or another type of notification method, you must have a notification provider installed or configured. You can either install an existing plugin or [create your own](../../../development/notification/create-notification-provider.md).
|
||||
|
||||
This document has an example using the [SendGrid](../../../plugins/notifications/sendgrid.mdx) plugin.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Create a Subscriber
|
||||
|
||||
To subscribe to and handle an event, you must create a subscriber.
|
||||
|
||||
:::tip
|
||||
|
||||
You can learn more about subscribers in the [Subscribers](../../../development/events/subscribers.mdx) documentation.
|
||||
|
||||
:::
|
||||
|
||||
Create the file `src/subscribers/claim-order.ts` with the following content:
|
||||
|
||||
```ts title=src/subscribers/claim-order.ts
|
||||
type InjectedDependencies = {
|
||||
// TODO add necessary dependencies
|
||||
}
|
||||
|
||||
class ClaimOrderSubscriber {
|
||||
constructor(container: InjectedDependencies) {
|
||||
// TODO subscribe to event
|
||||
}
|
||||
}
|
||||
|
||||
export default ClaimOrderSubscriber
|
||||
```
|
||||
|
||||
You’ll be adding in the next step the necessary dependencies to the subscriber.
|
||||
|
||||
:::info
|
||||
|
||||
You can learn more about [dependency injection](../../../development/fundamentals/dependency-injection.md) in this documentation.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Subscribe to the Event
|
||||
|
||||
In this step, you’ll subscribe to the `order-update-token.created` event to send the customer a notification about their order edit.
|
||||
|
||||
There are two ways to do this:
|
||||
|
||||
### Method 1: Using the NotificationService
|
||||
|
||||
If the notification provider you’re using already implements the logic to handle this event, you can subscribe to the event using the `NotificationService`:
|
||||
|
||||
```ts title=src/subscribers/claim-order.ts
|
||||
import { NotificationService } from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
notificationService: NotificationService
|
||||
}
|
||||
|
||||
class ClaimOrderSubscriber {
|
||||
constructor({ notificationService }: InjectedDependencies) {
|
||||
notificationService.subscribe(
|
||||
"order-update-token.created",
|
||||
"<NOTIFICATION_PROVIDER_IDENTIFIER>"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ClaimOrderSubscriber
|
||||
```
|
||||
|
||||
Where `<NOTIFICATION_PROVIDER_IDENTIFIER>` is the identifier for your notification provider.
|
||||
|
||||
:::info
|
||||
|
||||
You can learn more about handling events with the Notification Service using [this documentation](../../../development/notification/create-notification-provider.md).
|
||||
|
||||
:::
|
||||
|
||||
### Method 2: Using the EventBusService
|
||||
|
||||
If the notification provider you’re using isn’t configured to handle this event, or you want to implement some other custom logic, you can subscribe to the event using the `EventBusService`:
|
||||
|
||||
```ts title=src/subscribers/claim-order.ts
|
||||
import { EventBusService } from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService
|
||||
}
|
||||
|
||||
class ClaimOrderSubscriber {
|
||||
constructor({ eventBusService }: InjectedDependencies) {
|
||||
eventBusService.subscribe(
|
||||
"order-update-token.created",
|
||||
this.handleRequestClaimOrder
|
||||
)
|
||||
}
|
||||
|
||||
handleRequestClaimOrder = async (data) => {
|
||||
// TODO: handle event
|
||||
}
|
||||
}
|
||||
|
||||
export default ClaimOrderSubscriber
|
||||
```
|
||||
|
||||
When using this method, you’ll have to handle the logic of sending the confirmation email to the customer inside the handler function, which in this case is `handleRequestClaimOrder`.
|
||||
|
||||
The `handleRequestClaimOrder` event receives a `data` object as a parameter. This object holds the following properties:
|
||||
|
||||
1. `old_email`: The email associated with the orders.
|
||||
2. `new_customer_id`: The ID of the customer claiming the orders.
|
||||
3. `orders`: An array of the order IDs that the customer is requesting to claim.
|
||||
4. `token`: A verification token. This token is used to later verify the claim request and associate the order with the customer.
|
||||
|
||||
In this method, you should typically send an email to the customer’s old email. In the email, you should link to a page in your storefront and pass the `token` as a parameter.
|
||||
|
||||
The page would then send a request to the backend to verify that the `token` is valid and associate the order with the customer. You can read more about how to implement this in your storefront in [this documentation](../storefront/implement-claim-order.mdx).
|
||||
|
||||
---
|
||||
|
||||
## Example: Using SendGrid
|
||||
|
||||
For example, you can implement this subscriber to send emails using SendGrid:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts title=src/subscribers/claim-order.ts
|
||||
import { EventBusService } from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService,
|
||||
sendgridService: any
|
||||
}
|
||||
|
||||
class ClaimOrderSubscriber {
|
||||
protected sendGridService: any
|
||||
|
||||
constructor({
|
||||
eventBusService,
|
||||
sendgridService,
|
||||
}: InjectedDependencies) {
|
||||
this.sendGridService = sendgridService
|
||||
eventBusService.subscribe(
|
||||
"order-update-token.created",
|
||||
this.handleRequestClaimOrder
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
handleRequestClaimOrder = async (data) => {
|
||||
this.sendGridService.sendEmail({
|
||||
templateId: "order-claim-confirmation",
|
||||
from: "hello@medusajs.com",
|
||||
to: data.old_email,
|
||||
dynamic_template_data: {
|
||||
link: `http://example.com/confirm-order-claim/${data.token}`,
|
||||
// other data...
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default ClaimOrderSubscriber
|
||||
```
|
||||
|
||||
Notice how the `token` is passed to the storefront link as a parameter.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Implement claim-order flow in your storefront](../storefront/implement-claim-order.mdx)
|
||||
@@ -0,0 +1,261 @@
|
||||
---
|
||||
description: 'Learn how to send an order confirmation email to the customer. This guide uses SendGrid as an example Notification provider.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
# How to Send Order Confirmation Email
|
||||
|
||||
In this document, you’ll learn how to send an order confirmation email to the customer.
|
||||
|
||||
## Overview
|
||||
|
||||
When an order is placed, the `order.placed` event is triggered. You can listen to this event in a subscriber to perform an action, such as send the customer an order confirmation email.
|
||||
|
||||
This guide explains how to create the subscriber and how to use SendGrid to send the confirmation email. SendGrid is only used to illustrate how the process works, but you’re free to use any other notification service.
|
||||
|
||||
:::note
|
||||
|
||||
SendGrid is already configured to send emails when an order has been placed. So, by installing and configuring the plugin, you don't need to actually handle sending the order confirmation email. It's used as an example here to illustrate the process only.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Backend
|
||||
|
||||
It’s assumed you already have the Medusa backend installed. If not, you can either use the [create-medusa-app command](../../../create-medusa-app.mdx) to install different Medusa tools, including the backend, or [install the backend only](../../../development/backend/install.mdx).
|
||||
|
||||
### Event Bus Module
|
||||
|
||||
The event bus module trigger the event to the listening subscribers. So, it’s required to have an event bus module installed and configured on your Medusa backend.
|
||||
|
||||
The [Local Event Bus module](../../../development/events/modules/local.md) works in a development environment. For production, it’s recommended to use the [Redis Event Bus module](../../../development/events/modules/redis.md).
|
||||
|
||||
### Notification Provider
|
||||
|
||||
As mentioned in the overview, this guide illustrates how to send the email using SendGrid. If you intend to follow along, you must have the [SendGrid plugin](../../../plugins/notifications/sendgrid.mdx) installed and configured.
|
||||
|
||||
You can also find other available Notification provider plugins in the [Plugins directory](https://medusajs.com/plugins/), or [create your own](../../../development/notification/create-notification-provider.md).
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Create the Subscriber
|
||||
|
||||
To subscribe to and handle an event, you must create a subscriber.
|
||||
|
||||
:::note
|
||||
|
||||
You can learn more about subscribers in the [Subscribers documentation](../../../development/events/subscribers.mdx).
|
||||
|
||||
:::
|
||||
|
||||
Create the file `src/subscribers/order-confirmation.ts` with the following content:
|
||||
|
||||
```ts title=src/subscribers/order-confirmation.ts
|
||||
type InjectedDependencies = {
|
||||
// TODO add necessary dependencies
|
||||
}
|
||||
|
||||
class OrderConfirmationSubscriber {
|
||||
constructor(container: InjectedDependencies) {
|
||||
// TODO subscribe to event
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderConfirmationSubscriber
|
||||
```
|
||||
|
||||
You’ll be adding in the next step the necessary dependencies to the subscriber.
|
||||
|
||||
:::note
|
||||
|
||||
You can learn more about dependency injection in [this documentation](../../../development/fundamentals/dependency-injection.md).
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Subscribe to the Event
|
||||
|
||||
In this step, you’ll subscribe to the `order.placed` event to send the customer an order confirmation email.
|
||||
|
||||
There are two ways to do this:
|
||||
|
||||
### Method 1: Using the NotificationService
|
||||
|
||||
If the notification provider you’re using already implements the logic to handle this event, you can subscribe to the event using the `NotificationService`:
|
||||
|
||||
```ts title=src/subscribers/order-confirmation.ts
|
||||
import { NotificationService } from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
notificationService: NotificationService
|
||||
}
|
||||
|
||||
class OrderConfirmationSubscriber {
|
||||
constructor({ notificationService }: InjectedDependencies) {
|
||||
notificationService.subscribe(
|
||||
"order.placed",
|
||||
"<NOTIFICATION_PROVIDER_IDENTIFIER>"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderConfirmationSubscriber
|
||||
```
|
||||
|
||||
Where `<NOTIFICATION_PROVIDER_IDENTIFIER>` is the identifier for your notification provider.
|
||||
|
||||
:::note
|
||||
|
||||
You can learn more about handling events with the Notification Service using [this documentation](../../../development/notification/create-notification-provider.md).
|
||||
|
||||
:::
|
||||
|
||||
### Method 2: Using the EventBusService
|
||||
|
||||
If the notification provider you’re using isn’t configured to handle this event, or you want to implement some other custom logic, you can subscribe to the event using the `EventBusService`:
|
||||
|
||||
```ts title=src/subscribers/order-confirmation.ts
|
||||
import { EventBusService } from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService
|
||||
}
|
||||
|
||||
class OrderConfirmationSubscriber {
|
||||
constructor({ eventBusService }: InjectedDependencies) {
|
||||
eventBusService.subscribe(
|
||||
"order.placed",
|
||||
this.handleOrderConfirmation
|
||||
)
|
||||
}
|
||||
|
||||
handleOrderConfirmation = async (
|
||||
data: Record<string, any>
|
||||
) => {
|
||||
// TODO: handle event
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderConfirmationSubscriber
|
||||
```
|
||||
|
||||
When using this method, you’ll have to handle the logic of sending the order confirmation email to the customer inside the handler function, which in this case is `handleOrderConfirmation`.
|
||||
|
||||
## Step 3: Handle the Event
|
||||
|
||||
The `handleOrderConfirmation` event receives a `data` object as a parameter. This object holds two properties:
|
||||
|
||||
- `id`: the ID of the order that was placed.
|
||||
- `no_notification`: a boolean value indicating whether the customer should receive notifications about the order or not.
|
||||
|
||||
In this method, you should typically send an email to the customer if `no_notification` is enabled.
|
||||
|
||||
To retrieve the order's details, you can add the `OrderService` into `InjectedDependencies` and use it within `handleOrderConfirmation`. For example:
|
||||
|
||||
```ts title=src/subscribers/order-confirmation.ts
|
||||
import { EventBusService, OrderService } from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService
|
||||
orderService: OrderService
|
||||
}
|
||||
|
||||
class OrderConfirmationSubscriber {
|
||||
protected readonly orderService_: OrderService
|
||||
|
||||
constructor({
|
||||
eventBusService,
|
||||
orderService,
|
||||
}: InjectedDependencies) {
|
||||
this.orderService_ = orderService
|
||||
eventBusService.subscribe(
|
||||
"order.placed",
|
||||
this.handleOrderConfirmation
|
||||
)
|
||||
}
|
||||
|
||||
handleOrderConfirmation = async (
|
||||
data: Record<string, any>
|
||||
) => {
|
||||
const order = await this.orderService_.retrieve(data.id, {
|
||||
// you can include other relations as well
|
||||
relations: ["items"],
|
||||
})
|
||||
// TODO: handle event
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderConfirmationSubscriber
|
||||
```
|
||||
|
||||
After retrieving the order, you can add the logic necessary to send the email. In the email, you can include any content you want. For example, you can show the order's items or the order's status.
|
||||
|
||||
### Example: Using SendGrid
|
||||
|
||||
:::note
|
||||
|
||||
This example is only used to illustrate how the functionality can be implemented. As mentioned in the introduction, there's actually no need to implement this subscriber if you have the SendGrid plugin installed and configured, as it will automatically handle it.
|
||||
|
||||
:::
|
||||
|
||||
For example, you can implement this subscriber to send emails using SendGrid:
|
||||
|
||||
```ts title=src/subscribers/order-confirmation.ts
|
||||
import { EventBusService, OrderService } from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService
|
||||
orderService: OrderService
|
||||
sendgridService: any
|
||||
}
|
||||
|
||||
class OrderConfirmationSubscriber {
|
||||
protected readonly orderService_: OrderService
|
||||
protected readonly sendgridService_: any
|
||||
|
||||
constructor({
|
||||
eventBusService,
|
||||
orderService,
|
||||
sendgridService,
|
||||
}: InjectedDependencies) {
|
||||
this.orderService_ = orderService
|
||||
this.sendgridService_ = sendgridService
|
||||
eventBusService.subscribe(
|
||||
"order.placed",
|
||||
this.handleOrderConfirmation
|
||||
)
|
||||
}
|
||||
|
||||
handleOrderConfirmation = async (
|
||||
data: Record<string, any>
|
||||
) => {
|
||||
const order = await this.orderService_.retrieve(data.id, {
|
||||
// you can include other relations as well
|
||||
relations: ["items"],
|
||||
})
|
||||
this.sendgridService_.sendEmail({
|
||||
templateId: "order-confirmation",
|
||||
from: "hello@medusajs.com",
|
||||
to: order.email,
|
||||
dynamic_template_data: {
|
||||
// any data necessary for your template...
|
||||
items: order.items,
|
||||
status: order.status,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderConfirmationSubscriber
|
||||
```
|
||||
|
||||
Notice that you should replace the values in the object passed to the `sendEmail` method:
|
||||
|
||||
- `templateId`: Should be the ID of your order confirmation email template in SendGrid.
|
||||
- `from`: Should be the from email.
|
||||
- `to`: Should be the email associated with the order.
|
||||
- `data`: Should be an object holding any data that should be passed to your SendGrid email template.
|
||||
150
www/apps/docs/content/modules/orders/claims.md
Normal file
150
www/apps/docs/content/modules/orders/claims.md
Normal file
@@ -0,0 +1,150 @@
|
||||
---
|
||||
description: "Learn about claims, how the claim process is implemented in the Medusa backend, and a claim’s relation to other entities."
|
||||
---
|
||||
|
||||
# Claims Architecture Overview
|
||||
|
||||
In this document, you’ll learn about claims, how the claim process is implemented in the Medusa backend, and a claim’s relation to other entities.
|
||||
|
||||
## Overview
|
||||
|
||||
An item that the customer ordered may be defected or does not match the original product they ordered. In those cases, a merchant can create a claim to handle this situation by either refunding the customer or replacing the item they got with a different one.
|
||||
|
||||
The Medusa core provides the necessary implementation and functionalities that allow you to integrate this process into your store.
|
||||
|
||||
---
|
||||
|
||||
## ClaimOrder Entity Overview
|
||||
|
||||
A claim is represented by the `ClaimOrder` entity. Some of its attributes include:
|
||||
|
||||
- `type`: a string indicating the type of the claim. Its value can be either `refund` or `replace`.
|
||||
- `payment_status`: a string indicating the status of the claim’s payment. Its possible values are indicated by the [ClaimPaymentStatus enum](../../references/entities/enums/ClaimPaymentStatus.md). This attribute is useful to check the status of the payment if the claim’s type is `refund`.
|
||||
- `fulfillment_status`: a string indicating the status of the claim’s fulfillment. Its possible values are indicated by the [ClaimFulfillmentStatus enum](../../references/entities/enums/ClaimFulfillmentStatus.md). This attribute is useful to check the status of the fulfillment if the claim’s type is `replace`.
|
||||
- `refund_amount`: an integer used to indicate the amount that should be refunded to the customer. This is only useful if the claim’s type is `refund`.
|
||||
- `canceled_at`: a date indicating when the claim was canceled.
|
||||
|
||||
There are other important attributes discussed in later sections. Check out the [full ClaimOrder entity in the entities reference](../../references/entities/classes/ClaimOrder.md).
|
||||
|
||||
---
|
||||
|
||||
## How are Claims Created
|
||||
|
||||
Claims are created in Medusa by an admin (typically a merchant). They are created on an order, and depending on the claim’s type the admin can specify details like the amount to be refunded, or the items to be returned and the new items to replace them.
|
||||
|
||||
You can create a claim either using the [Create Claim endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderclaims) or using the `ClaimService`'s [create method](../../references/services/classes/ClaimService.md#create). This section explains the process within the Create Claim endpoint, with a focus on the `create` method.
|
||||
|
||||
### Idempotency Key
|
||||
|
||||
An Idempotency Key is a unique key associated with a claim. It is generated when the claim creation process is started by the admin using the [Create Claim endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderclaims) and can be used to retry the claim creation safely if an error occurs. The idempotency key is stored in the `ClaimOrder` entity in the attribute `idempotency_key`.
|
||||
|
||||
You can learn more about idempotency keys [here](../../development/idempotency-key/overview.mdx).
|
||||
|
||||
### Create Claim Endpoint Process
|
||||
|
||||
The following flow is implemented within the Create Claim endpoint:
|
||||
|
||||

|
||||
|
||||
1. When the idempotency key’s recovery point is `started`, the creation of the claim is started using the `ClaimService`'s [create method](../../references/services/classes/ClaimService.md#create). If the claim is created successfully, the idempotency key’s recovery point is changed to `claim_created`. In the `create` method:
|
||||
1. If the type of the claim is `refund` and no refund amount is set, the refund amount is calculated based on the items in the claim using the `ClaimService`'s [getRefundTotalForClaimLinesOnOrder method](../../references/services/classes/ClaimService.md#getrefundtotalforclaimlinesonorder).
|
||||
2. If new items are specified to send to the customer, new line items, which are represented by the `LineItem` entity, are generated using the `LineItemService`'s [generate method](../../references/services/classes/LineItemService.md#generate). These line items are later attached to the claim when it’s created under the `additional_items` relation. Also, the quantity of these items are reserved from the product variant’s inventory using the `ProductVariantInventoryService`'s [reserveQuantity method](../../references/services/classes/ProductVariantInventoryService.md#reservequantity).
|
||||
3. The claim is created and saved.
|
||||
4. If there were additional items attached to the claim, tax lines are created for these items using the `TaxProviderService`'s [createTaxLines method](../../references/services/classes/TaxProviderService.md#createtaxlines).
|
||||
5. If a shipping method was chosen to send the additional items to the customer, the shipping method is created using the `ShippingOptionService`'s [createShippingMethod method](../../references/services/classes/ShippingOptionService.md#createshippingmethod) or updated if it already exists using the `ShippingOptionService`'s [updateShippingMethod method](../../references/services/classes/ShippingOptionService.md#updateshippingmethod).
|
||||
6. A claim item is created for each of the items specified in the claim. These are the items that were originally in the order and that the claim was created for. The claim items are created using the `ClaimItemService`'s [create method](../../references/services/classes/ClaimItemService.md#create).
|
||||
7. If a return shipping method is specified, a return is created using the `ReturnService`'s [create method](../../references/services/classes/ReturnService.md#create).
|
||||
2. When the idempotency key’s recovery point is `claim_created`, if the claim’s type is `refund`, the refund is processed using the `ClaimService`'s [processRefund method](../../references/services/classes/ClaimService.md#processrefund). If the method is refunded successfully, the `payment_status` attribute of the claim is set to `refunded`. The refund is created directly on the order the claim belongs to. The recovery point of the idempotency key is changed to `refund_handled` at the end of this process.
|
||||
3. When the idempotency key’s recovery point is `refund_handled`, if the claim is associated with a return, the return is automatically fulfilled using the `ReturnService`'s [fulfill method](../../references/services/classes/ReturnService.md#fulfill) as it will be handled by the customer. The order associated with the claim is then returned and the idempotency key is set to `finished`.
|
||||
|
||||
---
|
||||
|
||||
## Fulfill a Claim
|
||||
|
||||
If a claim’s type is `replace`, an admin can create a [fulfillment](./fulfillments.md) for the additional items that should be sent to the customer.
|
||||
|
||||
A fulfillment can be created either using the [Create Claim Fulfillment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderclaimsclaimfulfillments) or the `ClaimService`'s [createFulfillment method](../../references/services/classes/ClaimService.md#createfulfillment).
|
||||
|
||||
:::note
|
||||
|
||||
The endpoint handles updating the inventory and reservations. So, if you choose to use the `createFulfillment` method, you should implement that within your code.
|
||||
|
||||
:::
|
||||
|
||||
By default, when a fulfillment is created, the claim’s `fulfillment_status` is set to `fulfilled`. However, if any of the item’s quantity isn’t fulfilled successfully, the `fulfillment_status` is set to `requires_action`.
|
||||
|
||||
After creating a fulfillment, you can create a shipment for the fulfillment either using the [Create Claim Shipment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderclaimsclaimshipments) or the `ClaimService`'s [createShipment method](../../references/services/classes/ClaimService.md#createshipment). If only some of the items and their quantities are shipped, the `fulfillment_status` of the claim is set to `partially_shipped`. Otherwise, if all items and quantities are shipped, the `fulfillment_status` of the claim is set to `shipped`.
|
||||
|
||||
You can alternatively cancel a fulfillment either using the [Cancel Claim Fulfillment endpoint](https://docs.medusajs.com/api/admin#tag/Orders/operation/PostOrdersClaimFulfillmentsCancel) or the `ClaimService`'s [cancelFulfillment method](../../references/services/classes/ClaimService.md#cancelfulfillment). This would change the `fulfillment_status` of the claim to `canceled`.
|
||||
|
||||
---
|
||||
|
||||
## Handling a Claim's Return
|
||||
|
||||
A claim's return can be marked as received, which would adjust the inventory and change the status of the return. This process is explained within the [Returns documentation](./returns.md#mark-return-as-received-process).
|
||||
|
||||
---
|
||||
|
||||
## Cancel a Claim
|
||||
|
||||
An admin can cancel a claim if it hasn’t been refunded either using the [Cancel Claim endpoint](https://docs.medusajs.com/api/admin#orders_postordersclaimcancel) or the `ClaimService`'s [cancel method](../../references/services/classes/ClaimService.md#cancel).
|
||||
|
||||
If any fulfillments were created, they must be canceled first. Similarly, if the claim is associated with a return, the return must be canceled first.
|
||||
|
||||
After the claim is canceled, the claim’s `fulfillment_status` is set to `canceled`.
|
||||
|
||||
---
|
||||
|
||||
## Relation to Other Entities
|
||||
|
||||
This section includes relations that weren’t mentioned in other sections.
|
||||
|
||||
### Order
|
||||
|
||||
A claim belongs to an [order](./orders.md), which is the order it was created for. An order is represented by the `Order` entity.
|
||||
|
||||
You can access the order’s ID using the `order_id` attribute of the claim. You can also access the order by expanding the `order` relation and accessing `claim.order`.
|
||||
|
||||
### ClaimItem
|
||||
|
||||
A claim’s items are represented by the `ClaimItem` entity. A claim can have more than one claim item.
|
||||
|
||||
You can access a claim’s items by expanding the `claim_items` relation and accessing `claim.claim_items`.
|
||||
|
||||
### LineItem
|
||||
|
||||
A claim’s additional items that should be sent to the customer are represented by the `LineItem` entity. A claim can have more than one additional item.
|
||||
|
||||
You can access a claim’s additional items by expanding the `additional_items` relation and accessing `claim.additional_items`.
|
||||
|
||||
### Return
|
||||
|
||||
If a claim’s type is `replace`, it will be associated with a [return](./returns.md). A return is represented by the `Return` entity.
|
||||
|
||||
You can access the return by expanding the `return_order` relation and accessing `claim.return_order`.
|
||||
|
||||
### Address
|
||||
|
||||
If a claim’s type is `replace`, it can be associated with a shipping address. A shipping address is represented by the `Address` entity.
|
||||
|
||||
You can access the shipping address’s ID using the `shipping_address_id` of the claim. You can also access the shipping address by expanding the `shipping_address` relation and accessing `claim.shipping_address`.
|
||||
|
||||
### ShippingMethod
|
||||
|
||||
If a claim’s type is `replace`, it can be associated with more than one [shipping method](../carts-and-checkout/shipping.md#shipping-method) which are used to ship the additional items. A shipping method is represented by the `ShippingMethod` entity.
|
||||
|
||||
You can access the claim’s shipping methods by expanding the `shipping_methods` relation and accessing `claim.shipping_methods`.
|
||||
|
||||
### Fulfillment
|
||||
|
||||
If a claim’s type is `replace`, it can be associated with more than one fulfillment which are created to fulfill the additional items. A fulfillment is represented by the `Fulfillment` entity.
|
||||
|
||||
You can access the claim’s fulfillment by expanding the `fulfillments` relation and accessing `claim.fulfillments`.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage claims using REST APIs](./admin/manage-claims.mdx)
|
||||
- [Orders architecture overview](./orders.md)
|
||||
- [Returns architecture overview](./claims.md)
|
||||
74
www/apps/docs/content/modules/orders/draft-orders.md
Normal file
74
www/apps/docs/content/modules/orders/draft-orders.md
Normal file
@@ -0,0 +1,74 @@
|
||||
---
|
||||
description: "Learn about draft orders, process around draft orders, and their relation to other entities in the Medusa backend."
|
||||
---
|
||||
|
||||
# Draft Orders Architecture Overview
|
||||
|
||||
In this document, you’ll learn about draft orders, process around draft orders, and their relation to other entities in the Medusa backend.
|
||||
|
||||
## Overview
|
||||
|
||||
Merchants may need to manually create orders without any involvement from the customer. This can be useful if the order is being created through a channel that isn’t integrated within your commerce system, or for some reason the customer can’t create the order themselves.
|
||||
|
||||
In Medusa, these types of orders are called draft orders. An admin or a merchant can create a draft order that holds all the details of the order. Then, the draft order can be later transformed into an actual order.
|
||||
|
||||
---
|
||||
|
||||
## DraftOrder Entity Overview
|
||||
|
||||
Some of the `DraftOrder`'s attributes include:
|
||||
|
||||
- `status`: a string indicating the status of the draft order. Its values can be:
|
||||
- `open`: the draft order is created, but hasn’t been completed.
|
||||
- `completed`: the draft order is completed. A draft order is considered completed when the payment for the order has been captured and an order has been created from the draft order.
|
||||
- `display_id`: a string that can be used as the displayed ID to customers and merchants.
|
||||
- `canceled_at`: a date indicating when the draft order was canceled.
|
||||
- `completed_at`: a date indicating when the draft order was completed.
|
||||
- `no_notification_order`: a boolean indicating whether the customer should receive notifications when the order is updated.
|
||||
|
||||
There are other important attributes discussed in later sections. Check out the [full DraftOrder entity in the entities reference](../../references/entities/classes/DraftOrder.md).
|
||||
|
||||
---
|
||||
|
||||
## How Draft Orders Work
|
||||
|
||||
You have full freedom in how you choose to implement creating draft orders. This section explains how it’s created in the Medusa backend using the [Create Draft Order](https://docs.medusajs.com/api/admin#draft-orders_postdraftorders) and [Register Payment](https://docs.medusajs.com/api/admin#draft-orders_postdraftordersdraftorderregisterpayment) endpoints.
|
||||
|
||||
A draft order is created using the `DraftOrderService`'s [create method](../../references/services/classes/DraftOrderService.md#create). Within that method, a cart is created along with it. The cart is used to store the order’s details, such as the draft order’s items, shipping options, and more. The cart has the type `draft_order`.
|
||||
|
||||
Since the draft order is associated with a cart, the process implemented in the Medusa backend around completing the draft order is pretty similar to that of completing a cart.
|
||||
|
||||
The payment must be authorized before the cart can be completed, which can be done using the `CartService`'s [authorizePayment method](../../references/services/classes/CartService.md#authorizepayment). Once the payment is authorized, the order can be created using the `OrderService`'s [createFromCart method](../../references/services/classes/OrderService.md#createfromcart).
|
||||
|
||||
:::note
|
||||
|
||||
In the Register Payment endpoint, the `system` payment method is used by default as the payment session of the cart. This means that the authorization and capturing of the payment don’t actually trigger any processes with existing payment processors integrated into your Medusa backend. It’s expected that the merchant will handle these processes manually.
|
||||
|
||||
:::
|
||||
|
||||
The draft order can then be completed using the `DraftOrderService`'s [registerCartCompletion method](../../references/services/classes/DraftOrderService.md#registercartcompletion). This would update its status to `completed` and would set the `order_id` attribute of the draft order. Finally, you can capture the payment of the order that was created using the `OrderService`'s [capturePayment method](../../references/services/classes/OrderService.md#capturepayment).
|
||||
|
||||
Once the order is created and the draft order is completed, the created order can be processed and handled the same as orders created by customers.
|
||||
|
||||
---
|
||||
|
||||
## Relation to Other Entities
|
||||
|
||||
### Cart
|
||||
|
||||
A draft order is associated with a [cart](../carts-and-checkout/cart.md) that is used to set the items in the draft order, shipping method, and more. A cart is represented by the `Cart` entity.
|
||||
|
||||
You can access the ID of the draft order’s cart using the `cart_id` attribute. You can also access the cart by expanding the `cart` relation and accessing `draft_order.cart`.
|
||||
|
||||
### Order
|
||||
|
||||
A draft order is associated with an [order](./orders.md) that is created once the draft order is completed. An order is represented by the `Order` entity.
|
||||
|
||||
You can access the ID of the order using the `order_id` attribute. You can also access the order by expanding the `order` relation and accessing `draft_order.order`.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage draft orders using REST APIs](./admin/manage-draft-orders.mdx)
|
||||
- [Order Architecture Overview](./orders.md)
|
||||
118
www/apps/docs/content/modules/orders/fulfillments.md
Normal file
118
www/apps/docs/content/modules/orders/fulfillments.md
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
description: "Learn about Fulfillments, how they’re used in your Medusa backend, and their relation to other entities."
|
||||
---
|
||||
|
||||
# Fulfillments Architecture Overview
|
||||
|
||||
In this document, you’ll learn about Fulfillments, how they’re used in your Medusa backend, and their relation to other entities.
|
||||
|
||||
## Overview
|
||||
|
||||
Fulfillments are used to ship items, typically to a customer. Fulfillments can be used in orders, returns, swaps, and more.
|
||||
|
||||
Fulfillments are processed within Medusa by a [fulfillment provider](../carts-and-checkout/backend/add-fulfillment-provider.md). The fulfillment provider handles creating, validating, and processing the fulfillment, among other functionalities. Typically, a fulfillment provider would be integrated with a third-party service that handles the actual shipping of the items.
|
||||
|
||||
When a fulfillment is created for one or more item, shipments can then be created for that fulfillment. These shipments can then be tracked using tracking numbers, providing customers and merchants accurate details about a shipment.
|
||||
|
||||
---
|
||||
|
||||
## Fulfillment Entity Overview
|
||||
|
||||
Some of the `Fulfillment` entity’s attributes include:
|
||||
|
||||
- `provider_id`: a string indicating the ID of the fulfillment provider that processes this fulfillment. You can also access the provider by expanding the `provider` relation and accessing `fulfillment.provider`.
|
||||
- `location_id`: a string indicating where the fulfillment is being made from. When paired with the Stock Location module in the Medusa backend, this would be the ID of a `StockLocation`.
|
||||
- `no_notification`: a boolean value indicating whether the customer should receive notifications for fulfillment updates.
|
||||
- `data`: an object that can hold any data relevant for the fulfillment provider.
|
||||
- `shipped_at`: a date indicating when the fulfillment was shipped.
|
||||
- `canceled_at`: a date indicating when the fulfillment was canceled.
|
||||
|
||||
There are other important attributes discussed in later sections. Check out the [full Fulfillment entity in the entities reference](../../references/entities/classes/Fulfillment.md).
|
||||
|
||||
---
|
||||
|
||||
## TrackingLink Entity Overview
|
||||
|
||||
When a shipment is created from a fulfillment, it is represented by the `TrackingLink` entity. This entity has the following attributes:
|
||||
|
||||
- `tracking_number`: a string indicating a tracking number that allows customers and merchants to track the status of the shipment. Typically, this would be a tracking number retrieved from a third-party fulfillment service.
|
||||
- `url`: an optional string indicating a URL that can be used to track the shipment.
|
||||
- `fulfillment_id`: The ID of the fulfillment this tracking link is associated with. You can also access the fulfillment by expanding the `fulfillment` relation and accessing `tracking_link.fulfillment`.
|
||||
|
||||
You can access the tracking numbers of a fulfillment in the `tracking_numbers` attribute. You can also access the tracking links by expanding the `tracking_links` relation and accessing `fulfillment.tracking_link`.
|
||||
|
||||
---
|
||||
|
||||
## Fulfillments in Other Processes
|
||||
|
||||
This section explains how a fulfillment can play a role in processes related to other entities and flows.
|
||||
|
||||
### Orders
|
||||
|
||||
A fulfillment is used to ship the items to the customer. Typically, the merchant would create a fulfillment, then create a shipment (tracking link) from that fulfillment.
|
||||
|
||||
If a fulfillment is created for an order, it’s associated with the order using the `order_id` attribute. You can also access the fulfillment’s order by expanding the `order` relation and accessing `fulfillment.order`.
|
||||
|
||||
A fulfillment’s status is stored in the `Order` entity’s `fulfillment_status` attribute, which can be one of the following values:
|
||||
|
||||
- `not_fulfilled`: no fulfillment has been created for the order.
|
||||
- `partially_fulfilled`: fulfillments have been created for some items in the order, but not all.
|
||||
- `fulfilled`: fulfillments have been created for all items in the order.
|
||||
- `partially_shipped`: shipments have been created for fulfillments, but not for all items in the order.
|
||||
- `shipped`: shipments have been created for fulfillments for all items in the order.
|
||||
- `partially_returned`: some items in the order have been returned.
|
||||
- `returned`: all items in the order have been returned.
|
||||
- `canceled`: the fulfillment has been canceled.
|
||||
- `requires_action`: a fulfillment has been created, but it requires some additional action.
|
||||
|
||||
You can learn more about how fulfillments are used in orders in the [Orders Architecture documentation](./orders.md#fulfillments-in-orders).
|
||||
|
||||
### Returns
|
||||
|
||||
A fulfillment is used to return the item from the customer. Typically, the fulfillment process for returns would be automated, as the customer is expected to handle it.
|
||||
|
||||
If a fulfillment is created for a return, it’s associated with the order and not with the return. The order’s `fulfillment_status` will be either `partially_returned` or `returned`, based on how many items were returned.
|
||||
|
||||
### Swaps
|
||||
|
||||
A fulfillment is used to send customers new items as part of a swap. Typically, the merchant would create a fulfillment, then create a shipment (tracking link) from that fulfillment.
|
||||
|
||||
If a fulfillment is created for a swap, it’s associated with the swap using the `swap_id` attribute. You can also access the fulfillment’s swap by expanding the `swap` relation and accessing `fulfillment.swap`.
|
||||
|
||||
A fulfillment’s status is stored in the `Swap` entity’s `fulfillment_status` attribute, which can be one of the following values:
|
||||
|
||||
- `not_fulfilled`: no fulfillment has been created for the swap.
|
||||
- `fulfilled`: a fulfillment has been created for the swap.
|
||||
- `partially_shipped`: shipments have been created for fulfillments, but not for all items in the swap.
|
||||
- `shipped`: shipments have been created for the fulfillment for all items in the swap.
|
||||
- `canceled`: the fulfillment has been canceled.
|
||||
- `requires_action`: the fulfillment has been created, but it requires some additional action.
|
||||
|
||||
You can learn more about fulfillments are used in swaps in the [Swaps Architecture documentation](./swaps.md#handling-swap-fulfillment).
|
||||
|
||||
### Claims
|
||||
|
||||
A fulfillment is used to send customers additional items as part of a claim. Typically, the merchant would create a fulfillment, then create a shipment (tracking link) from that fulfillment.
|
||||
|
||||
If a fulfillment is created for a claim, it’s associated with the claim using the `claim_order_id` attribute. You can also access the fulfillment’s claim by expanding the `claim_order` relation and accessing `fulfillment.claim_order`.
|
||||
|
||||
A fulfillment’s status is stored in the `Claim` entity’s `fulfillment_status` attribute, which can be one of the following values:
|
||||
|
||||
- `not_fulfilled`: no fulfillment has been created for the claim.
|
||||
- `partially_fulfilled`: fulfillments have been created for some items in the claim, but not all.
|
||||
- `fulfilled`: fulfillments have been created for all the items in the claim.
|
||||
- `partially_shipped`: shipments have been created for fulfillments, but not for all items in the claim.
|
||||
- `shipped`: shipments have been created for the fulfillment for all items in the claim.
|
||||
- `canceled`: the fulfillment has been canceled.
|
||||
- `requires_action`: the fulfillment has been created, but it requires some additional action.
|
||||
|
||||
You can learn more about fulfillments are used in claims in the [Claims Architecture documentation](./claims.md#fulfill-a-claim).
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Orders architecture overview](./orders.md)
|
||||
- [Swaps architecture overview](./swaps.md)
|
||||
- [Claims architecture overview](./claims.md)
|
||||
- [Returns architecture overview](./returns.md)
|
||||
302
www/apps/docs/content/modules/orders/orders.md
Normal file
302
www/apps/docs/content/modules/orders/orders.md
Normal file
@@ -0,0 +1,302 @@
|
||||
---
|
||||
description: "Learn about the orders architecture, how they’re created, and their relation to other entities."
|
||||
---
|
||||
|
||||
# Orders Architecture Overview
|
||||
|
||||
In this document, you’ll learn about the orders architecture, how they’re created, and their relation to other entities.
|
||||
|
||||
## Overview
|
||||
|
||||
Orders are placed by customers who purchase items from your store. They involve intricate commerce operations related to inventory, fulfillment, payment, and more.
|
||||
|
||||
Medusa supports order features such as order editing, creating swaps for orders, returning orders, and more. These features allow merchants to handle and automate Return Merchandise Authorization (RMA) flows.
|
||||
|
||||
:::note
|
||||
|
||||
As the Order domain is large in features and details, some features such as Returns or Swaps will not be discussed within this documentation page. Instead, they’ll be discussed in their own documentation pages.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Order Entity Overview
|
||||
|
||||
Some of the attributes of the `Order` entity include:
|
||||
|
||||
- `fulfillment_status`: a string indicating the status of the order’s fulfillment. Its possible values can determine whether all items have been fulfilled, shipped, or returned.
|
||||
- `payment_status`: a string indicating the status of the order’s payment. Its possible values can determine whether the payment of the order has been captured or refunded.
|
||||
- `status`: a string indicating the overall status of the order. Its values can be:
|
||||
- `pending`: this is the default status of the order after it has been created.
|
||||
- `completed`: the order is marked as completed. A merchant typically marks the order as completed after the order has been fulfilled and paid.
|
||||
- `refunded`: the order has been refunded.
|
||||
- `archived`: the order is archived. This status can only be attained after the order has been completed or refunded.
|
||||
- `canceled`: the order has been canceled. An order can’t be canceled if it has been refunded or if any of its relations, such as fulfillment or swaps, are not canceled.
|
||||
- `display_id`: a string indicating an incremental ID that can be displayed to the customer or internally to merchants.
|
||||
- `canceled_at`: a date indicating when the order was canceled.
|
||||
- `no_notification`: a boolean value indicating whether the customer should receive notifications when the order is updated.
|
||||
- `external_id`: a string indicating an ID of the order in an external system. This can be useful if you’re migrating your orders from another commerce system or you’re linking your order to a third-party service.
|
||||
|
||||
There are other important attributes discussed in later sections. Check out the full [Order entity in the entities reference](../../references/entities/classes/Order.md).
|
||||
|
||||
---
|
||||
|
||||
## How are Orders Created
|
||||
|
||||
You have full freedom in how you create your orders. Within the Medusa backend, there are two defined ways when an order is created:
|
||||
|
||||
1. Using a cart: The customer adds products to their cart and go through the checkout process to place the order. Learn about the [cart completion process here](../carts-and-checkout/cart.md#cart-completion-process).
|
||||
2. Using draft orders: the merchant can create draft orders without the customer’s involvement. This includes a very similar process of adding products to the draft order, supplying the shipping and billing addresses, and more. The draft order can later be turned into a regular order.
|
||||
|
||||
---
|
||||
|
||||
## Payments in Orders
|
||||
|
||||
In the cart completion process, or when you use the `OrderService`'s method [createFromCart](../../references/services/classes/OrderService.md#createfromcart), the cart’s payment is also associated with the order by setting the `order_id` of the payment to the newly created order’s ID.
|
||||
|
||||
An order can have more than one payment. You can access the order’s payments by expanding the `payments` relation and accessing `order.payments`.
|
||||
|
||||
By default, the payment will be authorized but not captured. Some payment processor plugins, such as the Stripe plugin, allow changing this behavior to automatically capture the payment. You can also do that within your custom payment processor.
|
||||
|
||||
In the default scenario, the merchant would have to capture that payment manually, which would change the `payment_status` of the order. The payment can be captured using the `PaymentService`'s [capture method](../../references/services/classes/PaymentService.md#capture).
|
||||
|
||||
After a payment has been captured, it can be refunded either fully or a specific amount of it. This is useful if items of an order has been returned or swapped, or if an order has been edited. The payment can be refunded using the `PaymentService`'s [refund method](../../references/services/classes/PaymentService.md#refund).
|
||||
|
||||
The Medusa backend also provides payment admin APIs that you can use to retrieve, capture, and refund the payment.
|
||||
|
||||
---
|
||||
|
||||
## Fulfillments in Orders
|
||||
|
||||
After an order is placed, you can create [fulfillments](./fulfillments.md) for the items in the order. You can fulfill all items or some items. A fulfillment is represented by the `Fulfillment` entity, and it’s associated with the order through the `order_id` attribute of the fulfillment.
|
||||
|
||||
Creating fulfillments changes the `fulfillment_status` of the order. If all items were fulfilled, the status changes to `fulfilled`. If only some items are fulfilled, the status changes to `partially_fulfilled`.
|
||||
|
||||
You can access an order’s fulfillments by expanding the `fulfillments` relation and accessing `order.fulfillments`.
|
||||
|
||||
After a fulfillment is created, you can mark it as shipped. This would change the `fulfillment_status` of the order to `shipped` if all items were shipped, or `partially_shipped` if only some items were shipped.
|
||||
|
||||
A fulfillment can instead be canceled, changing the `fulfillment_status` to `canceled`.
|
||||
|
||||
If one or some items in an order are returned, the `fulfillment_status` is set to `partially_returned`. If all items were returned, the `fulfillment_status` is set to `returned`.
|
||||
|
||||
The Medusa backend provides these functionalities through the admin APIs. You can also use the `OrderService`'s methods to perform these functionalities in a custom flow, such as the [createFulfillment](../../references/services/classes/OrderService.md#createfulfillment) or [createShipment](../../references/services/classes/OrderService.md#createshipment) methods.
|
||||
|
||||
---
|
||||
|
||||
## Order Totals Calculations
|
||||
|
||||
By default, the `Order` entity doesn’t hold any details regarding the totals. These are computed and added to the order instance using the `OrderService`'s [decorateTotals method](../../references/services/classes/OrderService.md#decoratetotals). There's also a dedicated method in the `OrderService`, [retrieveWithTotals](../../references/services/classes/OrderService.md#retrievewithtotals), attaching the totals to the order instance automatically. It is recommended to use this method by default when you need to retrieve the order.
|
||||
|
||||
The order’s totals are calculated based on the content and context of the order. This includes the order’s region, whether tax-inclusive pricing is enabled, the chosen shipping methods, and more.
|
||||
|
||||
The calculated order’s totals include:
|
||||
|
||||
- `shipping_total`: The total of the chosen shipping methods, with taxes.
|
||||
- `discount_total`: The total of the applied discounts.
|
||||
- `raw_discount_total`: The total of the applied discounts without rounding.
|
||||
- `item_tax_total`: The total applied taxes on the order’s items.
|
||||
- `gift_card_total`: The total gift card amount applied on the order. If there are any taxes applied on the gift cards, they’re deducted from the total.
|
||||
- `gift_card_tax_total`: The total taxes applied on the order’s gift cards.
|
||||
- `tax_total`: The total taxes applied (the sum of `shipping_tax_total`, `item_tax_total`, and `gift_card_tax_total`).
|
||||
- `subtotal`: The total of the items without taxes or discounts.
|
||||
- `refunded_total`: the total amount refunded to the customer, if any.
|
||||
- `paid_total`: the total amount paid by the customer.
|
||||
- `refundable_amount`: the amount that can be refunded to the customer. This would be the subtraction of `refunded_total` from `paid_total`.
|
||||
- `total`: The overall total of the order.
|
||||
|
||||
:::note
|
||||
|
||||
If you have tax-inclusive pricing enabled, you can learn about other available total fields [here](../taxes/inclusive-pricing.md#retrieving-tax-amounts).
|
||||
|
||||
:::
|
||||
|
||||
The order’s totals are retrieved by default in all the order’s [store](https://docs.medusajs.com/api/store#orders) and [admin](https://docs.medusajs.com/api/admin#orders) APIs.
|
||||
|
||||
---
|
||||
|
||||
## Order Edits
|
||||
|
||||
After an order has been placed, it can be edited to add, remove, or change ordered items.
|
||||
|
||||
:::tip
|
||||
|
||||
Order Edits don't cover edits to other details in the order, such as the shipping address, as these can be done by the admin at any point. This is only focused on the line items in the cart.
|
||||
|
||||
:::
|
||||
|
||||
Typically, a merchant would edit the order and send the edit request to the customer with the changes being made. Any additional payments required can be made when the customer accepts the order edit.
|
||||
|
||||
A merchant may also choose to force the edit on the order, by-passing the customer’s confirmation.
|
||||
|
||||

|
||||
|
||||
Although this process is implemented in this flow within the Medusa backend, there is no requirement for you to actually follow it. For example, you can allow the customer or a third-party service to create and manage the order edit.
|
||||
|
||||
The Medusa backend provides the [order edit admin APIs](https://docs.medusajs.com/api/admin#order-edits), but you can also use the [OrderEditService](../../references/services/classes/OrderEditService.md) to perform the same functionalities in a custom flow.
|
||||
|
||||
Order edits are represented by the `OrderEdit` entity. This entity is linked to the order through the `order_id` attribute. You can access an order’s edits by expanding the `edits` relation and accessing `order.edits`. Notice that an order can have multiple edits during its lifecycle, but it can’t have more than one ongoing edit.
|
||||
|
||||
Some of the `OrderEdit`'s other attributes include:
|
||||
|
||||
- `internal_note`: a string that can hold a note to be visible only internally.
|
||||
- `created_by`: a string that typically should hold the ID of who created the order edit. For example, if the merchant created the order edit, it should hold the ID of a `User`. There are no restrictions on what this attribute can hold, so you can also add here third-party IDs or names if necessary.
|
||||
- `requested_by`: a string that typically should hold the ID of who requested the order edit. Similar to the `created_by` attribute, there are no restrictions on what value this attribute can actually hold.
|
||||
- `confirmed_by`: a string that typically should hold the ID of who confirmed the order edit. Similar to the `created_by` attribute, there are no restrictions on what value this attribute can actually hold.
|
||||
- `declined_by`: a string that typically should hold the ID of who declined the order edit. Similar to the `created_by` attribute, there are no restrictions on what value this attribute can actually hold.
|
||||
|
||||
There are other attributes explained in other sections. You can also check out the full [OrderEdit entity in the entities reference](../../references/entities/classes/OrderEdit.md).
|
||||
|
||||
### Item Changes
|
||||
|
||||
Changes to the items in the orders are stored in the `OrderItemChange` entity. Some of this entity’s attributes include:
|
||||
|
||||
- `order_edit_id`: The ID of the order edit this item change is linked to. The order edit can also be accessed by expanding the `order_edit` relation and accessing `itemChange.order_edit`.
|
||||
- `type`: a string indicating the type of change being made. Its value can be:
|
||||
- `item_add` meaning that a new item is being added to the order.
|
||||
- `item_remove` meaning that an item in the order is being removed.
|
||||
- `item_update` meaning that an item in the order is being updated. For example, its quantity is being changed.
|
||||
- `original_line_item_id`: The ID of the line item that this item change is targeting. This would be the item that should be deleted or updated. If a new item is being added, then this attribute will be null. The line item can also be accessed by expanding the `original_line_item` relation and accessing `itemChange.original_line_item`.
|
||||
- `line_item_id`: the ID of the new line item to replace the original one. This line item would hold the changes that should be applied on the original line item. The line item can also be accessed by expanding the `line_item` relation and accessing `itemChange.line_item`.
|
||||
|
||||
When the order edit is confirmed, the original line items are no longer linked to the order. On the other hand, the new line items are linked to the new order. The items’ history is preserved through the order edits. So, you can access the previous state of an order and its items by accessing `order.edits`.
|
||||
|
||||
### PaymentCollection
|
||||
|
||||
If the order edit requires additional payments from the customer, they are stored in a payment collection. A payment collection allows bundling more than one payment related to a single entity or flow. It is represented by the `PaymentCollection` entity, which has the following relations:
|
||||
|
||||
- `payment_sessions`: the payment sessions that are linked to the payment collection. Payment sessions are linked to a payment provider and are used to hold the status of a payment in a flow, such as the checkout flow.
|
||||
- `payments`: the payments that are linked to the payment collection. Payments are authorized amounts by the customer that can later be processed. For example, you can capture or refund a payment.
|
||||
|
||||
For order edits, you can authorize the entire payment collection that holds additional required payments when the customer confirms the order edit.
|
||||
|
||||
---
|
||||
|
||||
## Automating RMA Flows
|
||||
|
||||
Medusa provides the necessary infrastructure and tooling that allows automating RMA flows. Entities involved in the RMA flows can include:
|
||||
|
||||
- Returns: Return an item from the customer to the merchant.
|
||||
- Swap: Swap an item with another. This involves returning the original item from the customer and shipping a new item to the customer.
|
||||
- Claim: Allow a customer to refund or replace an item in their order if it’s faulty or for other reasons.
|
||||
|
||||
The Medusa backend facilitates automating these flows by allowing the customer to submit a [return](https://docs.medusajs.com/api/store#returns_postreturns) or [swap](https://docs.medusajs.com/api/store#swaps_postswaps) requests through the store APIs. The merchant can then review and handle these requests. This eliminates the need for the customer to perform the same action through customer support or other means.
|
||||
|
||||
You can also integrate these flows within bigger processes that trigger requesting or creating these flows. It can be done through core APIs, [custom endpoints](../../development/endpoints/overview.mdx), or [custom services](../../development/services/overview.mdx). You can also listen to events related to orders such as [Order](../../development/events/events-list.md#order-events) or [Swap](../../development/events/events-list.md#swap-events) events with [subscribers](../../development/events/subscribers.mdx) to perform asynchronous actions.
|
||||
|
||||
---
|
||||
|
||||
## Relations to Other Entities
|
||||
|
||||
This section includes relations that weren’t mentioned in other sections.
|
||||
|
||||
### Cart
|
||||
|
||||
An order can be associated with a [cart](../carts-and-checkout/overview.mdx), which is the cart it is created from. A cart is represented by the `Cart` entity.
|
||||
|
||||
You can access the cart’s ID using the `cart_id` attribute. You can also access the cart by expanding the `cart` relation and accessing `order.cart`.
|
||||
|
||||
### LineItem
|
||||
|
||||
An order has items, which are represented by the `LineItem` entity. These are typically the same line items created in the cart, with the `order_id` attribute of the line item set to the ID of the order.
|
||||
|
||||
You can access an order’s items by expanding the `items` relation and accessing `order.items`.
|
||||
|
||||
### Customer
|
||||
|
||||
An order is associated with the [customer](../customers/overview.mdx) that placed the order. A customer is represented by the `Customer` entity.
|
||||
|
||||
You can access the customer’s ID using the `customer_id` attribute. You can also access the customer by expanding the `customer` relation and accessing `order.customer`.
|
||||
|
||||
### SalesChannel
|
||||
|
||||
An order can belong to a [sales channel](../sales-channels/overview.mdx). This typically would be the sales channel of the cart the order was created from. A sales channel is represented by the `SalesChannel` entity.
|
||||
|
||||
The sales channel’s ID is stored in the `sales_channel_id` attribute of the order. You can also access the sales channel by expanding the `sales_channel` relation and accessing `order.sales_channel`.
|
||||
|
||||
### Region
|
||||
|
||||
An order belongs to a [region](../regions-and-currencies/overview.mdx). Typically, this would be the region of the cart the order is created from. A region is represented by the `Region` entity.
|
||||
|
||||
You can access the region’s ID using the `region_id` attribute. You can also access the region by expanding the `region` relation and accessing `order.region`.
|
||||
|
||||
### Currency
|
||||
|
||||
An order is associated to a [currency](../regions-and-currencies/overview.mdx). Typically, this would be the currency of the region the order belongs to. A currency is represented by the `Currency` entity.
|
||||
|
||||
You can access the currency code using the `currency_code` attribute. You can also access the currency by expanding the `currency` relation and accessing `order.currency`.
|
||||
|
||||
### Billing Address
|
||||
|
||||
An order can have a billing address, which is represented by the `Address` entity.
|
||||
|
||||
You can access the billing address’s ID using the `billing_address_id` attribute. You can also access the billing address by expanding the `billing_address` relation and accessing `order.billing_address`.
|
||||
|
||||
### Shipping Address
|
||||
|
||||
An order can have a shipping address, which is represented by the `Address` entity.
|
||||
|
||||
You can access the shipping address’s ID using the `shipping_address_id` attribute. You can also access the shipping address by expanding the `shipping_address` relation and accessing `order.shipping_address`.
|
||||
|
||||
### Discount
|
||||
|
||||
[Discounts](../discounts/overview.mdx) can be applied on an order. Typically, these would be the discounts that were applied on the cart associated with the order. A discount is represented by the `Discount` entity.
|
||||
|
||||
You can access the order’s discounts by expanding the `discounts` relation and accessing `order.discounts`.
|
||||
|
||||
### GiftCard
|
||||
|
||||
[Gift cards](../gift-cards/overview.mdx) can be applied on an order. Typically, these would be the gift cards that were applied on the cart associated with the order. A gift card is represented by the `GiftCard` entity.
|
||||
|
||||
You can access the order’s gift cards by expanding the `gift_cards` relation and accessing `order.gift_cards`.
|
||||
|
||||
### GiftCardTransaction
|
||||
|
||||
A gift card transaction is created when a gift card is used on the cart. It is used to deduct an amount from the original balance of the gift card after the order is placed, and to keep track of the history of a gift card’s transactions. It’s represented by the `GiftCardTransaction` entity and it’s associated with the order’s ID using the `order_id` attribute on the entity.
|
||||
|
||||
You can access an order’s gift card transactions by expanding the `gift_card_transactions` relation and accessing `order.gift_card_transactions`.
|
||||
|
||||
### ShippingMethod
|
||||
|
||||
An order is associated with [shipping methods](../carts-and-checkout/shipping.md#shipping-method). Typically, these would be the shipping methods chosen during checkout. An order can have more than one shipping method. A shipping method is represented by the `ShippingMethod` entity.
|
||||
|
||||
You can access the order’s shipping method by expanding the `shipping_methods` relation and accessing `order.shipping_methods`.
|
||||
|
||||
### Returns
|
||||
|
||||
An order can be associated with more than one [return](./returns.md). For example, a customer may request to return items separately or gradually. A return is represented by the `Return` entity.
|
||||
|
||||
You can access the order’s returns by expanding the `returns` relation and accessing `order.returns`.
|
||||
|
||||
### ClaimOrder
|
||||
|
||||
An order can be associated with more than one [claim](./claims.md). A claim is represented by the `ClaimOrder` entity.
|
||||
|
||||
You can access the order’s claims by expanding the `claims` relation and accessing `order.claims`.
|
||||
|
||||
### Refund
|
||||
|
||||
An order can be associated with more than one refund. A refund is represented by the `Refund` entity.
|
||||
|
||||
You can access the order’s refunds by expanding the `refunds` relation and accessing `order.refunds`.
|
||||
|
||||
### Swap
|
||||
|
||||
An order can be associated with more than one [swap](./swaps.md). A swap is represented by the `Swap` entity.
|
||||
|
||||
You can access the order’s swaps by expanding the `swap` relation and accessing `order.swap`.
|
||||
|
||||
### DraftOrder
|
||||
|
||||
An order can be associated with a [draft order](./draft-orders.md). This would be the draft order that the order was created from.
|
||||
|
||||
The draft order’s ID is stored in the `draft_order_id` attribute. You can also access the draft order by expanding the `draft_order` relation and accessing `order.draft_order`.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage orders](./admin/manage-orders.mdx)
|
||||
- [How to edit an order](./admin/edit-order.mdx)
|
||||
- [How to handle order edits on the storefront](./storefront/handle-order-edits.mdx)
|
||||
- [How to Implement Claim Order Flow in the storefront](./storefront/implement-claim-order.mdx)
|
||||
343
www/apps/docs/content/modules/orders/overview.mdx
Normal file
343
www/apps/docs/content/modules/orders/overview.mdx
Normal file
@@ -0,0 +1,343 @@
|
||||
---
|
||||
description: "Customers place orders to purchase products from an ecommerce business. Learn about the available features and guides."
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import Icons from '@theme/Icon';
|
||||
|
||||
# Orders
|
||||
|
||||
Customers place orders to purchase products from an ecommerce business. This overview introduces the available features related to orders.
|
||||
|
||||
:::note
|
||||
|
||||
Not a developer? Check out the [Orders user guide](../../user-guide/orders/index.md).
|
||||
|
||||
:::
|
||||
|
||||
## Features
|
||||
|
||||
### Order Management
|
||||
|
||||
Admins can manage orders placed by customers, including capturing payment and fulfilling items in the order. Admins can also export orders into CSV files.
|
||||
|
||||
Customers can view their previous orders.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/admin/manage-orders',
|
||||
label: 'Admin: Manage Orders',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage orders using Admin APIs.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/orders/manage',
|
||||
label: 'User Guide: Manage Orders',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Manage orders in Medusa Admin.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/orders/export',
|
||||
label: 'User Guide: Export Orders',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Export orders into CSV files in Medusa admin.'
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/orders/payments',
|
||||
label: 'User Guide: Manage Payments',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Manage an order\'s payment in Medusa Admin.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/orders/fulfillments',
|
||||
label: 'User Guide: Manage Fulfillment',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Manage an order\'s fulfillment in Medusa Admin.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/storefront/retrieve-order-details',
|
||||
label: 'Storefront: Retrieve Order Details',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: "Learn the different ways to retrieve an order's details",
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
### Edit Orders
|
||||
|
||||
Admins can perform edits on items in an order, such as add, remove, or update items. Admins can request confirmation from the customer or force apply the edit.
|
||||
|
||||
Customers can review order edit requests and authorize additional payments if necessary.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/admin/edit-order',
|
||||
label: 'Admin: Edit an Order',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to edit an order using Admin APIs.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/orders/edit',
|
||||
label: 'User Guide: Edit Order',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Edit an order in Medusa Admin.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/storefront/handle-order-edits',
|
||||
label: 'Storefront: Order Edits',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Handle order edits in a storefront.'
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
### Draft Orders
|
||||
|
||||
Admins can create draft orders that don’t require involvement from a customer. They can specify all details including items in the order, payment method, and more.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/admin/manage-draft-orders',
|
||||
label: 'Admin: Manage Draft Orders',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage draft orders using Admin APIs.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/orders/edit',
|
||||
label: 'User Guide: Draft Orders',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Manage draft orders in Medusa Admin.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://docs.medusajs.com/api/admin#draft-orders_getdraftorders',
|
||||
label: 'Admin APIs: Draft Orders',
|
||||
customProps: {
|
||||
icon: Icons['server-solid'],
|
||||
description: 'Check available Admin REST APIs for Draft Orders.'
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
### Returns, Swaps, and Claims
|
||||
|
||||
Admins can return order items, or create swaps to return an item to be replaced by a new one.
|
||||
|
||||
Customers can also request to return or swap items. This allows for implementing an automated Return Merchandise Authorization (RMA) flow.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/admin/manage-returns',
|
||||
label: 'Admin: Manage Returns',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage returns using Admin APIs.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/admin/manage-swaps',
|
||||
label: 'Admin: Manage Swaps',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage swaps using Admin APIs.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/admin/manage-claims',
|
||||
label: 'Admin: Manage Claims',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage claims using Admin APIs.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/orders/returns',
|
||||
label: 'User Guide: Manage Returns',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Manage order returns in Medusa Admin.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/orders/exchange',
|
||||
label: 'User Guide: Exchanges',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Manage order exchanges in Medusa Admin.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/orders/claims',
|
||||
label: 'User Guide: Manage Claims',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Manage order claims in Medusa Admin.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/storefront/create-return',
|
||||
label: 'Storefront: Create a Return',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a return as a customer.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/storefront/create-swap',
|
||||
label: 'Storefront: Create a Swap',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a swap as a customer.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://docs.medusajs.com/api/store#returns',
|
||||
label: 'Storefront APIs: Returns',
|
||||
customProps: {
|
||||
icon: Icons['server-solid'],
|
||||
description: 'Check available Storefront REST APIs for Returns.'
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Understand the Architecture
|
||||
|
||||
Learn how order-related entities are built, their relation to other modules, and more.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders',
|
||||
label: 'Architecture: Order',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Order architecture.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/swaps',
|
||||
label: 'Architecture: Swap',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Swap architecture.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/returns',
|
||||
label: 'Architecture: Return',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Return architecture.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/claims',
|
||||
label: 'Architecture: Claim',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Claim architecture.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/draft-orders',
|
||||
label: 'Architecture: Draft Order',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Draft Order architecture.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/fulfillments',
|
||||
label: 'Architecture: Fulfillment',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Fulfillment architecture.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Related Modules
|
||||
|
||||
Discover Order’s relation to other modules in Medusa
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/overview',
|
||||
label: 'Carts and Checkout',
|
||||
customProps: {
|
||||
icon: Icons['shopping-cart-solid'],
|
||||
description: 'Customers can place an order using a virtual cart.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/products/overview',
|
||||
label: 'Products',
|
||||
customProps: {
|
||||
icon: Icons['tag-solid'],
|
||||
description: 'Customers can browse products to purchase them.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/sales-channels/overview',
|
||||
label: 'Sales Channels',
|
||||
customProps: {
|
||||
icon: Icons['channels-solid'],
|
||||
description: 'Orders can be associated with specific channels.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
135
www/apps/docs/content/modules/orders/returns.md
Normal file
135
www/apps/docs/content/modules/orders/returns.md
Normal file
@@ -0,0 +1,135 @@
|
||||
---
|
||||
description: "Learn about returns, how the return process is implemented in the Medusa backend, and a return’s relation to other entities."
|
||||
---
|
||||
|
||||
# Returns Architecture Overview
|
||||
|
||||
In this document, you’ll learn about returns, how the return process is implemented in the Medusa backend, and a return’s relation to other entities.
|
||||
|
||||
## Overview
|
||||
|
||||
After a customer receives an item they ordered, they might want to return it back. This process includes returning the item into the commerce store, and refunding the payment back to the customer.
|
||||
|
||||
The Medusa core provides the necessary implementation and functionalities that allow you to integrate this process into your store and automate the Return Merchandise Authorization (RMA) flow.
|
||||
|
||||
---
|
||||
|
||||
## Return Entity Overview
|
||||
|
||||
Some of the `Return` entity’s attributes include:
|
||||
|
||||
- `status`: A string indicating the status of the return. Its value can be one of the following:
|
||||
- `requested`: The customer requested the return.
|
||||
- `requires_action`: The return couldn’t be marked as received because there’s a mismatch between the items specified in the return request and the received items.
|
||||
- `received`: the merchant marks the return as received.
|
||||
- `canceled`: the merchant canceled the return.
|
||||
- `refund_amount`: A number indicating the amount that should be refunded.
|
||||
- `received_at`: the date indicating when the return was marked as received.
|
||||
- `no_notification`: a boolean value indicating whether the customer should receive notification updates when there are any changes in the return.
|
||||
- `shipping_data`: this is a JSONB object that can hold any data related to the fulfillment associated with the return.
|
||||
|
||||
There are other important attributes discussed in later sections. Check out the [full Return entity in the entities reference](../../references/entities/classes/Return.md).
|
||||
|
||||
---
|
||||
|
||||
## Returns Process
|
||||
|
||||
Returns can be created in three ways:
|
||||
|
||||
1. Created directly, typically by a client or customer.
|
||||
2. Created automatically and linked to a swap when a swap is created. You can learn more about the overall swap process in the [Swaps documentation](./swaps.md). The Mark Return as Received section applies for swaps as well.
|
||||
3. Created automatically and linked to a claim when a claim is created. You can learn more about the overall claim process in the [Claims documentation] The Mark Return as Received section applies for claims as well.
|
||||
|
||||
### Idempotency Key
|
||||
|
||||
An Idempotency Key is a unique key associated with a return. It is generated when the return creation process is started by the customer and can be used to retry the return creation safely if an error occurs. The idempotency key is stored in the `Return` entity in the attribute `idempotency_key`.
|
||||
|
||||
You can learn more about idempotency keys [here](../../development/idempotency-key/overview.mdx).
|
||||
|
||||
### Return Creation Process Through the Customer
|
||||
|
||||
This section explains how the return is created by the customer or any type of client. This is the process created within the Medusa core.
|
||||
|
||||
The following process occurs within the Create Return storefront endpoint:
|
||||
|
||||

|
||||
|
||||
1. The customer creates a return, specifying the items they want to return and optionally the shipping option they want to use to return the items. This is done using the `ReturnService`'s [create method](../../references/services/classes/ReturnService.md#create).
|
||||
2. If they specify the return shipping option they want to use, a shipping method is created from the chosen shipping option and the return is automatically fulfilled in the backend using the `ReturnService`'s [fulfill method](../../references/services/classes/ReturnService.md#fulfill).
|
||||
|
||||
After this process, the return will be available for the merchant or the admin to view and handle it. The merchant can either mark the return as received or cancel the return.
|
||||
|
||||
### Mark Return as Received Process
|
||||
|
||||
Marking a return as received would refund the amount to the customer and adjust the store’s inventory for the returned items.
|
||||
|
||||
The following process occurs within the [Receive Return admin endpoint](https://docs.medusajs.com/api/admin#returns_postreturnsreturnreceive):
|
||||
|
||||

|
||||
|
||||
1. The return is marked as received using the `ReturnService`'s receive method. In this method:
|
||||
1. The return’s status is checked to ensure it’s not canceled or received. If so, the process is terminated with an error.
|
||||
2. The received items are validated to ensure they match the items that were previously requested to be returned. If there’s a mismatch, the return’s status is set to `requires_more`. This is useful in situations where a custom refund amount is requested, but the returned items don’t match the requested items.
|
||||
3. If there’s no mismatch issue, the return’s status is set to `received`.
|
||||
4. The inventory of the returned items is adjusted using the `ProductVariantInventoryService`'s [method adjustInventory](../../references/services/classes/ProductVariantInventoryService.md#adjustinventory)
|
||||
2. After the return is marked as received, if the return is associated with a swap, the `SwapService`'s [registerReceived method](../../references/services/classes/SwapService.md#registerreceived) is used to validate the return, emit the swap event `received`, and return the swap.
|
||||
3. On the other hand, after the return is marked as received, if the return is associated with an order, the `OrderService`'s [registerReturnReceived method](../../references/services/classes/OrderService.md#registerreturnreceived). In this method:
|
||||
1. If the amount that is expected to be refunded is greater than the amount that can be refunded, the `fulfillment_status` of the order is set to `requires_action`. And the process is terminated.
|
||||
2. If there are no validation issues, the payment is refunded and the fulfillment status is set to `returned` if all items of the order were returned, or `partially_returned` if only some items were returned.
|
||||
|
||||
### Cancel a Return
|
||||
|
||||
The merchant can cancel a return if it hasn’t be marked as `received` before. This can be done either using the `ReturnService`'s [cancel method](../../references/services/classes/ReturnService.md#cancel) or using the [Cancel Return endpoint](https://docs.medusajs.com/api/admin#returns_postreturnsreturncancel).
|
||||
|
||||
Canceling a return would change its status to canceled.
|
||||
|
||||
---
|
||||
|
||||
## RMA Automation with Returns
|
||||
|
||||
Giving the client control over the creation of a return allows businesses to automate their RMA flow.
|
||||
|
||||
The client, typically the customer, creates the return, and specifies the shipping option they’ll use to return the item. The admin, typically the merchant, can view the requested return, mark it as received, and refund the payment to the customer. The core will also take care of adjusting the inventory automatically.
|
||||
|
||||

|
||||
|
||||
This removes any friction and support required between the client and the admin.
|
||||
|
||||
---
|
||||
|
||||
## Relation to Other Entities
|
||||
|
||||
This section includes relations that weren’t mentioned in other sections.
|
||||
|
||||
## Order
|
||||
|
||||
The return can be associated with an [order](./orders.md). An order is represented by the `Order` entity.
|
||||
|
||||
You can access the order’s ID using the `order_id` property. You can also access the order by expanding the `order` relation and accessing `return.order`.
|
||||
|
||||
### Swap
|
||||
|
||||
The return can be associated with a [swap](./swaps.md). A swap is represented by the `Swap` entity.
|
||||
|
||||
You can access the swap’s ID using the `swap_id` property. You can also access the swap by expanding the `swap` relation and accessing `return.swap`.
|
||||
|
||||
### ClaimOrder
|
||||
|
||||
The return can be associated with a [claim](./claims.md). A claim is represented by the `ClaimOrder` entity.
|
||||
|
||||
You can access the claim’s ID using the `claim_order_id` property. You can also access the claim by expanding the `claim_order` relation and accessing `return.claim_order`.
|
||||
|
||||
### ShippingMethod
|
||||
|
||||
The return can be associated with a [shipping method](../carts-and-checkout/shipping.md#shipping-method). This would be the shipping method the customer chose when they created the swap. A shipping method is represented by the `ShippingMethod` entity.
|
||||
|
||||
You can access the shipping method by expanding the `shipping_method` relation and accessing `return.shipping_method`.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage returns](./admin/manage-returns.mdx)
|
||||
- [Orders architecture overview](./orders.md)
|
||||
- [Swaps architecture overview](./swaps.md)
|
||||
- [Claims architecture overview](./claims.md)
|
||||
@@ -0,0 +1,234 @@
|
||||
---
|
||||
description: "Learn how to implement a create return flow in the storefront."
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Create a Return in the Storefront
|
||||
|
||||
In this document, you’ll learn how to implement a create return flow in the storefront.
|
||||
|
||||
## Overview
|
||||
|
||||
Customers may need to return items they received from an order they placed for different reasons, such as ordering an incorrect size of the item.
|
||||
|
||||
The Medusa backend allows automating the process of returning an item by providing the necessary mechanism that allows customers to create the return request themselves. This guide illustrates how you can implement that mechanism in your storefront.
|
||||
|
||||
The process of creating a return is as follows:
|
||||
|
||||
- Ask the customer to select the items they want to return. You can also allow customers to select the return shipping option to use to return the item.
|
||||
- Create the return in the Medusa backend.
|
||||
|
||||
:::note
|
||||
|
||||
Refunding the customer is handled by admins. You can learn how to implement or use this functionality in the [Manage Returns guide](../admin/manage-returns.mdx).
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It's assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
It's also assumed you already have a storefront set up. It can be a custom storefront or one of Medusa’s storefronts. If you don’t have a storefront set up, you can install the [Next.js Starter Template](../../../starters/nextjs-medusa-starter.mdx).
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client and JavaScript’s Fetch API.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client installed](../../../js-client/overview.md) and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Collecting Return Details
|
||||
|
||||
When a customer wants to create a return, they must choose the items they want to return. To display the items in the order, you can retrieve the order as explained in [this guide](./retrieve-order-details.mdx). You can then display the items in an order using `order.items`, which is an array of items.
|
||||
|
||||
### Showing Return Shipping Options
|
||||
|
||||
You can optionally allow customers to choose a return shipping option that they’ll use to return the items. To show the customers the available return shipping options, send a request to the Get [Shipping Options endpoint](https://docs.medusajs.com/api/store#shipping-options_getshippingoptions):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.shippingOptions.list({
|
||||
is_return: "true",
|
||||
})
|
||||
.then(({ shipping_options }) => {
|
||||
console.log(shipping_options.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useShippingOptions } from "medusa-react"
|
||||
|
||||
const ReturnShippingOptions = () => {
|
||||
const {
|
||||
shipping_options,
|
||||
isLoading,
|
||||
} = useShippingOptions({
|
||||
is_return: "true",
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{shipping_options?.length &&
|
||||
shipping_options?.length > 0 && (
|
||||
<ul>
|
||||
{shipping_options?.map((shipping_option) => (
|
||||
<li key={shipping_option.id}>
|
||||
{shipping_option.id}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReturnShippingOptions
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/shipping-options?is_return=true`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ shipping_options }) => {
|
||||
console.log(shipping_options.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint allows you to pass the `is_return` query parameter to indicate whether the shipping options should be return shipping options. You can learn about other available filters in the [API reference](https://docs.medusajs.com/api/store#shipping-options_getshippingoptions).
|
||||
|
||||
The request returns an array of shipping option objects.
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Create Return
|
||||
|
||||
You can create the return by sending a request to the [Create Return endpoint](https://docs.medusajs.com/api/store#returns_postreturns):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.returns.create({
|
||||
order_id,
|
||||
items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
return_shipping: {
|
||||
option_id,
|
||||
},
|
||||
})
|
||||
.then((data) => {
|
||||
console.log(data.return.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useCreateReturn } from "medusa-react"
|
||||
|
||||
const CreateReturn = () => {
|
||||
const createReturn = useCreateReturn()
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
createReturn.mutate({
|
||||
order_id,
|
||||
items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
return_shipping: {
|
||||
option_id,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CreateReturn
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/returns`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
order_id,
|
||||
items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
return_shipping: {
|
||||
option_id,
|
||||
},
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
console.log(data.return.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the following request body parameters:
|
||||
|
||||
- `order_id`: a string indicating the ID of the order to create the return for.
|
||||
- `items`: an array of objects, each object being an item from the order to return. Each object must have the following properties:
|
||||
- `item_id`: a string indicating the ID of the item in the order.
|
||||
- `quantity`: a number indicating the quantity to return.
|
||||
|
||||
You can optionally pass the `return_shipping` parameter, which is the return shipping option that the customer will use to return the item. It’s an object that has a required property `option_id`, which is a string indicating the ID of the return shipping option.
|
||||
|
||||
The request returns the created return as an object.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage returns as an admin](../admin/manage-returns.mdx)
|
||||
- [How to implement a create swap flow in a storefront](./create-swap.mdx)
|
||||
252
www/apps/docs/content/modules/orders/storefront/create-swap.mdx
Normal file
252
www/apps/docs/content/modules/orders/storefront/create-swap.mdx
Normal file
@@ -0,0 +1,252 @@
|
||||
---
|
||||
description: "Learn how to implement a create swap flow in a storefront."
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Create a Swap in the Storefront
|
||||
|
||||
In this document, you’ll learn how to implement a create swap flow in a storefront.
|
||||
|
||||
## Overview
|
||||
|
||||
Swaps allow customers to exchange items they ordered with new ones. This can be helpful if the customer ordered and received an item they didn’t like, if they ordered an incorrect size, or something similar.
|
||||
|
||||
The Medusa backend allows automating the process of exchanging an item with another by providing the necessary mechanism that allows customers to create the swap request themselves. This guide illustrates how you can implement that mechanism in your storefront.
|
||||
|
||||
The process of creating a swap is as follows:
|
||||
|
||||
- Ask the customer to select the items they want to replace, and which items they want to replace them with. You can also allow customers to select the return shipping option to use to return the item.
|
||||
- Create the swap in the Medusa backend.
|
||||
- Show a checkout flow using the swap’s cart. This allows the customer to provide their shipping details and authorize payment in a flow similar to that of placing an order.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It's assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
It's also assumed you already have a storefront set up. It can be a custom storefront or one of Medusa’s storefronts. If you don’t have a storefront set up, you can install the [Next.js Starter Template](../../../starters/nextjs-medusa-starter.mdx).
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client and JavaScript’s Fetch API.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client installed](../../../js-client/overview.md) and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Collecting Swap Details
|
||||
|
||||
When a customer wants to create a swap, they must choose the items they want to return or replace and the items they want to receive instead.
|
||||
|
||||
To display the items in the order, you can retrieve the order as explained in [this guide](./retrieve-order-details.mdx). You can then display the items in an order using `order.items`, which is an array of items.
|
||||
|
||||
To allow the customers to choose other items to replace the items from the order, you can show them the available products in your store to choose from them. You can learn how to retrieve products in your storefront using [this guide](../../products/storefront/show-products.mdx).
|
||||
|
||||
You can optionally allow customers to choose a return shipping option that they’ll use to return the items. You can learn how to retrieve return shipping options in [this guide](./create-return.mdx#showing-return-shipping-options).
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Create the Swap
|
||||
|
||||
After collecting the swap details in step 1, you can create a swap in the Medusa backend by sending a request to the [Create Swap endpoint](https://docs.medusajs.com/api/store#swaps_postswaps):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.swaps.create({
|
||||
order_id,
|
||||
return_items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
additional_items: [
|
||||
{
|
||||
variant_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
return_shipping_option,
|
||||
})
|
||||
.then(({ swap }) => {
|
||||
console.log(swap.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useCreateSwap } from "medusa-react"
|
||||
|
||||
const CreateSwap = () => {
|
||||
const createSwap = useCreateSwap()
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
createSwap.mutate({
|
||||
order_id,
|
||||
return_items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
additional_items: [
|
||||
{
|
||||
variant_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
return_shipping_option,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CreateSwap
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/swaps`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
order_id,
|
||||
return_items: [
|
||||
{
|
||||
item_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
additional_items: [
|
||||
{
|
||||
variant_id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
return_shipping_option,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ swap }) => {
|
||||
console.log(swap.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the following request body parameters:
|
||||
|
||||
- `order_id`: a string indicating the ID of the order that this swap is created for.
|
||||
- `return_items`: an array of objects, each object being the item to return. Each object should have the following properties:
|
||||
- `item_id`: a string indicating the ID of the item in the order.
|
||||
- `quantity`: a number indicating the quantity to return.
|
||||
- `additional_items`: an array of objects, each object being the new item to receive. Each object should have the following properties:
|
||||
- `variant_id`: a string indicating the ID of the product variant.
|
||||
- `quantity`: a number indicating the quantity to add.
|
||||
|
||||
You can optionally pass the `return_shipping_option` body parameter, which is a string indicating the ID of the shipping option.
|
||||
|
||||
The request returns the swap as an object.
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Complete Swap with Checkout Flow
|
||||
|
||||
The swap can be completed in the same flow as a checkout flow. Since a swap is associated with a cart, you can implement the checkout flow using the cart of the swap. You can access the cart of a swap in the swap object using `swap.cart`.
|
||||
|
||||
Since the Medusa backend knows the cart is associated with the swap, it will ensure that the flow is performed in the context of a swap. You can learn how to implement a checkout flow in your storefront using [this guide](../../carts-and-checkout/storefront/implement-checkout-flow.mdx).
|
||||
|
||||
:::note
|
||||
|
||||
When you complete the cart, the returned `type` field can be used to indicate the context of the checkout flow. In the case of a swap, the value of `type` will be `swap`.
|
||||
|
||||
:::
|
||||
|
||||
### Retrieve Swap by Cart ID
|
||||
|
||||
During your checkout flow, you might need to retrieve the swap using the cart’s ID. For example, if you want to display the swap’s details after the cart is successfully completed. You can do that using the [Get by Cart ID endpoint](https://docs.medusajs.com/api/store#swaps_getswapsswapcartid):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.swaps.retrieveByCartId(cartId)
|
||||
.then(({ swap }) => {
|
||||
console.log(swap.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useCartSwap } from "medusa-react"
|
||||
|
||||
const Swap = () => {
|
||||
const {
|
||||
swap,
|
||||
isLoading,
|
||||
} = useCartSwap(cartId)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{swap && <span>{swap.id}</span>}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Swap
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/swaps/${cartId}`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ swap }) => {
|
||||
console.log(swap.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the ID of the cart as a path parameter.
|
||||
|
||||
The request returns the swap as an object.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to implement a create return flow in a storefront](./create-return.mdx)
|
||||
- [How to retrieve order details in a storefront](./retrieve-order-details.mdx)
|
||||
@@ -0,0 +1,477 @@
|
||||
---
|
||||
description: 'Learn how to implement order-edit related features in the storefront using REST APIs. This includes showing the customer order-edit requests, authorizing additional payments, and confirming or declining order edits.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Handle an Order Edit in Storefront
|
||||
|
||||
In this document, you’ll learn how to allow a customer to confirm or decline an Order Edit.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
A merchant can request to edit an order to make changes to its items. The change can include removing an item, adding a new item, and changing the quantity of an item in the original order.
|
||||
|
||||
When the Order Edit is in the “request” state, it requires either a confirmation from the customer, or it can be force-confirmed by the merchant.
|
||||
|
||||
This guide focuses on how to use the Storefront APIs to implement the flow that allows a customer to either confirm or decline an Order Edit.
|
||||
|
||||
:::note
|
||||
|
||||
You can check out how to implement order editing using the Admin APIs in [this documentation](../admin/edit-order.mdx).
|
||||
|
||||
:::
|
||||
|
||||
### Scenarios
|
||||
|
||||
You want to implement the following functionalities in your storefront:
|
||||
|
||||
- List and show customers order-edit requests.
|
||||
- Confirm order edits and authorize any additional payment if necessary.
|
||||
- Decline order edits.
|
||||
|
||||
:::note
|
||||
|
||||
You can perform other functionalities related to order editing. To learn more, check out the API reference.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It's assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
It is also assumed you already have a storefront set up. It can be a custom storefront or one of Medusa’s storefronts. If you don’t have a storefront set up, you can install the [Next.js Starter Template](../../../starters/nextjs-medusa-starter.mdx).
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client and JavaScript’s Fetch API.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client installed](../../../js-client/overview.md) and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
### Previous Steps
|
||||
|
||||
You must have an existing order edit in the “request” state.
|
||||
|
||||
---
|
||||
|
||||
## Retrieve an Order Edit
|
||||
|
||||
You can retrieve a single order edit by its ID by sending a request to the [Get Order Edit](https://docs.medusajs.com/api/store#order-edits_getordereditsorderedit) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.orderEdits.retrieve(orderEditId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes)
|
||||
// show changed items to the customer
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useOrderEdit } from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const { order_edit, isLoading } = useOrderEdit(orderEditId)
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/order-edits/${orderEditId}`)
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes)
|
||||
// show changed items to the customer
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The request requires the order edit’s ID as a path parameter.
|
||||
|
||||
It returns the Order Edit as an object. Some of its important fields are:
|
||||
|
||||
- `order_id`: The ID of the order that this Order Edit belongs to.
|
||||
- `difference_due`: The amount to either be refunded or paid. If the amount is greater than 0, then the customer is required to pay an additional amount. If the amount is less than 0, then the merchant has to refund the difference to the customer.
|
||||
- `payment_collection_id`: The ID of the payment collection. This will be used to authorize additional payment if necessary.
|
||||
|
||||
:::note
|
||||
|
||||
You can learn more about what fields to expect in the [API reference](https://docs.medusajs.com/api/store#order-edits_getordereditsorderedit).
|
||||
|
||||
:::
|
||||
|
||||
### Show Changed Items
|
||||
|
||||
All data about changes to the original order’s items can be found in `order_edit.changes`. `changes` is an array of item changes. Each item change includes the following fields:
|
||||
|
||||
<!-- eslint-skip -->
|
||||
|
||||
```ts
|
||||
{
|
||||
type: string,
|
||||
line_item: LineItem | null,
|
||||
original_line_item: LineItem | null
|
||||
}
|
||||
```
|
||||
|
||||
`type` can be either:
|
||||
|
||||
- `item_add`: In this case, a new item is being added. `line_item` will be an item object and `original_line_item` will be `null`.
|
||||
- `item_update`: In this case, an item’s quantity in the original order is updated. `line_item` will be the updated item, and `original_line_item` will be the item in the original order. You can either just use `line_item` to show the new quantity, or show the customer a comparison between the old and new quantity using `original_line_item` as well.
|
||||
- `item_remove`: In this case, an item in the original order is removed. The `original_line_item` will be the item in the original order, and `line_item` will be `null`.
|
||||
|
||||
Here’s an example of how you can use this data to show the customer the requested edits to the order:
|
||||
|
||||
```tsx
|
||||
<ul>
|
||||
{orderEdit.changes.map((itemChange) => (
|
||||
<li key={itemChange.id}>
|
||||
<strong>
|
||||
{
|
||||
itemChange.line_item ?
|
||||
itemChange.line_item.title :
|
||||
itemChange.original_line_item.title
|
||||
}
|
||||
</strong>
|
||||
{itemChange.type === "added" && <span>New Item</span>}
|
||||
{itemChange.type === "removed" && (
|
||||
<span>Removed Item</span>
|
||||
)}
|
||||
{itemChange.type === "edited" &&
|
||||
<span>
|
||||
Edited Item
|
||||
Old Quantity: {itemChange.original_line_item.quantity}
|
||||
New Quantity: {itemChange.line_item.quantity}
|
||||
</span>}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Handle Payment
|
||||
|
||||
After viewing the changes in the order edit, the customer can choose to confirm or decline the order edit.
|
||||
|
||||
In case the customer wants to confirm the order edit, you must check whether a refund or an additional payment is required. You can check that by checking the value of `difference_due`.
|
||||
|
||||
### Refund Amount
|
||||
|
||||
If `difference_due` is less than 0, then the amount will be refunded to the customer by the merchant from the Medusa admin. No additional actions are required here before [completing the order edit](#complete-the-order-edit).
|
||||
|
||||
### Make Additional Payments
|
||||
|
||||
:::note
|
||||
|
||||
This section explains how to authorize the payment using one payment processor and payment session. However, payment collections allow customers to pay in installments or with more than one provider. You can learn more about how to do that using the [batch endpoints of the Payment APIs](https://docs.medusajs.com/api/store#payment-collections_postpaymentcollectionssessionsbatchauthorize)
|
||||
|
||||
:::
|
||||
|
||||
If `difference_due` is greater than 0, then additional payment from the customer is required. In this case, you must implement these steps to allow the customer to authorize the payment:
|
||||
|
||||
1. Show the customer the available payment processors. These can be retrieved from the details of [the region of the order](https://docs.medusajs.com/api/store#regions_getregions).
|
||||
2. When the customer selects the payment processor, initialize the payment session of that provider in the payment collection. You can do that by sending a request to the [Manage Payment Sessions](https://docs.medusajs.com/api/store#payment-collections_postpaymentcollectionspaymentcollectionsessionsbatch) endpoint, passing it the payment collection’s ID as a path parameter, and the payment processor's ID as a request body parameter:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
medusa.paymentCollections.managePaymentSession(paymentCollectionId, {
|
||||
provider_id,
|
||||
})
|
||||
.then(({ payment_collection }) => {
|
||||
console.log(payment_collection.payment_sessions)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useManagePaymentSession } from "medusa-react"
|
||||
|
||||
const OrderEditPayment = () => {
|
||||
const managePaymentSession = useManagePaymentSession(
|
||||
paymentCollectionId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleAdditionalPayment = (provider_id: string) => {
|
||||
managePaymentSession.mutate({
|
||||
provider_id,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEditPayment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(
|
||||
`<BACKEND_URL>/store/payment-collections/${paymentCollectionId}/sessions`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
provider_id,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ payment_collection }) => {
|
||||
console.log(payment_collection.payment_sessions)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
1. Show the customer the payment details form based on the payment session’s provider. For example, if the provider ID of a payment session is `stripe`, you must show Stripe’s card component to enter the customer’s card details.
|
||||
2. Authorize the payment using the payment processor. The [Authorize Payment Session](https://docs.medusajs.com/api/store#payment-collections_postpaymentcollectionssessionssessionauthorize) endpoint accepts the payment collection’s ID and the ID of the payment session as path parameters:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa
|
||||
.paymentCollection
|
||||
.authorizePaymentSession(
|
||||
paymentCollectionId,
|
||||
paymentSessionId
|
||||
)
|
||||
.then(({ payment_session }) => {
|
||||
console.log(payment_session.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAuthorizePaymentSession } from "medusa-react"
|
||||
|
||||
const OrderEditPayment = () => {
|
||||
const authorizePaymentSession = useAuthorizePaymentSession(
|
||||
paymentCollectionId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleAuthorizePayment = (paymentSessionId: string) => {
|
||||
authorizePaymentSession.mutate(paymentSessionId)
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEditPayment
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(
|
||||
`<BACKEND_URL>/store/payment-collection/${paymentCollectionId}` +
|
||||
`/sessions/${paymentSessionId}/authorize`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ payment_session }) => {
|
||||
console.log(payment_session.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
After performing the above steps, you can [complete the Order Edit](#complete-the-order-edit).
|
||||
|
||||
---
|
||||
|
||||
## Complete the Order Edit
|
||||
|
||||
To confirm and complete the order edit, send a request to the [Complete Order Edit](https://docs.medusajs.com/api/store#order-edits_postordereditsordereditcomplete) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.orderEdits.complete(orderEditId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.confirmed_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useCompleteOrderEdit } from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const completeOrderEdit = useCompleteOrderEdit(orderEditId)
|
||||
// ...
|
||||
|
||||
const handleCompleteOrderEdit = () => {
|
||||
completeOrderEdit.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/order-edits/${orderEditId}/complete`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.confirmed_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request accepts the order edit’s ID as a path parameter.
|
||||
|
||||
It returns the full Order Edit object. You can find properties related to the order confirmation, such as `order_edit.confirmed_at`.
|
||||
|
||||
After completing the order edit, the changes proposed in the Order Edit are reflected in the original order.
|
||||
|
||||
:::info
|
||||
|
||||
If the payment isn’t authorized first, the order edit completion will fail.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Decline an Order Edit
|
||||
|
||||
If the customer wants to decline the Order Edit, you can do that by sending a request to the Decline Order Edit endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.orderEdits.decline(orderEditId, {
|
||||
decline_reason: "I am not satisfied",
|
||||
})
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.declined_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useDeclineOrderEdit } from "medusa-react"
|
||||
|
||||
const OrderEdit = () => {
|
||||
const declineOrderEdit = useDeclineOrderEdit(orderEditId)
|
||||
// ...
|
||||
|
||||
const handleDeclineOrderEdit = () => {
|
||||
declineOrderEdit.mutate({
|
||||
declined_reason: "I am not satisfied",
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default OrderEdit
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(
|
||||
`<BACKEND_URL>/store/order-edits/${orderEditId}/decline`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
decline_reason: "I am not satisfied",
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.declined_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The request requires passing the order edit’s ID as a path parameter.
|
||||
|
||||
In the request body parameters, you can optionally pass the `decline_reason` parameter. It’s a string that indicates to the merchant the reason the customer declined the order edit.
|
||||
|
||||
If the Order Edit is declined, the changes requested in the Order Edit aren't reflected on the original order and no refund or additional payments are required.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Edit an order using Admin APIs](../admin/edit-order.mdx)
|
||||
@@ -0,0 +1,210 @@
|
||||
---
|
||||
description: 'Learn how to implement the order-claim flow in the storefront. This includes allowing customers to claim their orders, and verify a claim to an order.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Implement Claim Order Flow in Storefront
|
||||
|
||||
In this document, you’ll learn how to implement the claim order flow in a storefront to allow customers to claim their orders.
|
||||
|
||||
:::note
|
||||
|
||||
This flow was added starting from Medusa v1.7. You can learn more about upgrading in the [upgrade guide](../../../upgrade-guides/medusa-core/1-7-0.md).
|
||||
|
||||
:::
|
||||
|
||||
## Flow Overview
|
||||
|
||||
When a guest customer places an order, their order is not associated with any customer. The order is only associated with an email that the guest customer provides during checkout.
|
||||
|
||||
This email must be an email that isn’t used with an existing account. It can, however, be used to create another order as a guest customer.
|
||||
|
||||
After this customer registers with a different email and logs in, they can claim their order by providing the order’s ID. An email will then be sent to the email address associated with the order.
|
||||
|
||||
The email should contain a link to a page in the storefront, and the link should have a token as a parameter. This token will be used for verification.
|
||||
|
||||
The customer must then click the link in the email they received. If the token is valid, the order will be associated with the customer.
|
||||
|
||||

|
||||
|
||||
### What You’ll Learn
|
||||
|
||||
In this document, you’ll learn how to implement two parts of this flow:
|
||||
|
||||
1. Allow customers to claim their orders.
|
||||
2. Verify a claim to an order.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It's assumed that you already have a Medusa backend installed and set up. If not, you can follow the [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
It is also assumed you already have a storefront set up. It can be a custom storefront or one of Medusa’s storefronts. If you don’t have a storefront set up, you can install the [Next.js Starter Template](../../../starters/nextjs-medusa-starter.mdx).
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client installed](../../../js-client/overview.md) and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
### Handle Order Claim Request Event
|
||||
|
||||
When the customer requests to claim the order, an event will be triggered. You should subscribe to this event to send a confirmation email to the customer when the event is triggered.
|
||||
|
||||
You can learn how to implement this flow in [this documentation](../backend/handle-order-claim-event.md).
|
||||
|
||||
### Previous Steps
|
||||
|
||||
It is assumed you already have an order placed by a guest customer. You can refer to the [Cart](../../carts-and-checkout/storefront/implement-cart) and [Checkout](../../carts-and-checkout/storefront/implement-checkout-flow.mdx) implementation documentation to learn how to implement them in your storefront.
|
||||
|
||||
In addition, it is assumed you already have a logged-in customer before performing the steps in this document. You can refer to the [API reference](https://docs.medusajs.com/api/store#auth_postauth) for more details on that.
|
||||
|
||||
---
|
||||
|
||||
## Request to Claim an Order
|
||||
|
||||
When the customer wants to claim an order, they must supply its ID.
|
||||
|
||||
To allow the customer to claim an order, send a request to the Claim an Order endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.orders.requestCustomerOrders({
|
||||
order_ids: [
|
||||
order_id,
|
||||
],
|
||||
})
|
||||
.then(() => {
|
||||
// successful
|
||||
})
|
||||
.catch(() => {
|
||||
// an error occurred
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/orders/batch/customer/token`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
order_ids: [
|
||||
order_id,
|
||||
],
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
// successful
|
||||
})
|
||||
.catch(() => {
|
||||
// display an error to the customer
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request accepts as a body parameter the array `order_ids`. Each item in the array is the ID of an order that the customer wants to claim. You can pass more than one ID.
|
||||
|
||||
If the customer’s request has been processed successfully, the request returns a response with a `200` status code.
|
||||
|
||||
The customer at this point will receive an email with a link to verify their claim on the order.
|
||||
|
||||
---
|
||||
|
||||
## Manually Verify a Claim to an Order
|
||||
|
||||
The link in the email that the customer receives should be a page in your storefront that accepts a `token` query parameter.
|
||||
|
||||
Then, you send a request to the Verify Claim Order endpoint:
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.orders.confirmRequest({
|
||||
token,
|
||||
})
|
||||
.then(() => {
|
||||
// successful
|
||||
})
|
||||
.catch(() => {
|
||||
// an error occurred
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useGrantOrderAccess } from "medusa-react"
|
||||
|
||||
const ClaimOrder = () => {
|
||||
const grantOrderAccess = useGrantOrderAccess()
|
||||
// ...
|
||||
|
||||
const handleVerifyOrderClaim = (token: string) => {
|
||||
grantOrderAccess.mutate(({
|
||||
token,
|
||||
}))
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default ClaimOrder
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/orders/customer/confirm`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
token,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
// successful
|
||||
})
|
||||
.catch(() => {
|
||||
// display an error to the customer
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This request accepts as a body parameter the string `token`. This would be the token passed as a parameter to your storefront page through the link in the email.
|
||||
|
||||
If the verification is successful, the order will now be associated with the customer and the customer will be able to see it among their orders.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Send a confirmation email to claim an order](../backend/handle-order-claim-event.md)
|
||||
@@ -0,0 +1,245 @@
|
||||
---
|
||||
description: "Learn the different ways you can retrieve and view a customer’s orders, whether they're a guest customer or logged-in."
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Retrieve Order Details on the Storefront
|
||||
|
||||
In this document, you’ll learn the different ways you can retrieve and view a customer’s orders, whether they're a guest customer or logged-in.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It's assumed that you already have a Medusa backend installed and set up. If not, you can follow our [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
It's also assumed you already have a storefront set up. It can be a custom storefront or one of Medusa’s storefronts. If you don’t have a storefront set up, you can install the [Next.js Starter Template](../../../starters/nextjs-medusa-starter.mdx).
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client and JavaScript’s Fetch API.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client installed](../../../js-client/overview.md) and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.mdx) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.mdx#usage).
|
||||
|
||||
---
|
||||
|
||||
## Retrieve Order by ID
|
||||
|
||||
Retrieving an order by its ID is useful for different scenarios, such as using an order details page. You can use this method for both logged in and guest customers.
|
||||
|
||||
You can retrieve an order by its ID using the [Get Order endpoint](https://docs.medusajs.com/api/store#orders_getordersorder):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.orders.retrieve(orderId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useOrder } from "medusa-react"
|
||||
|
||||
const Order = () => {
|
||||
const {
|
||||
order,
|
||||
isLoading,
|
||||
} = useOrder(orderId)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{order && <span>{order.display_id}</span>}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Order
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/orders/${orderId}`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the order’s ID to be passed as a path parameter. You can utilize the [expand](https://docs.medusajs.com/api/store#expanding-fields) and [fields](https://docs.medusajs.com/api/store#selecting-fields) query parameters to select parameters and relations to return.
|
||||
|
||||
The request returns the order as an object.
|
||||
|
||||
---
|
||||
|
||||
## Retrieve Order by Display ID
|
||||
|
||||
Display IDs allow you to show human-readable IDs to your customers. Retrieving an order by its display ID is useful in many situations, such as allowing customers to look up their orders with a search field. This method of retrieving an order can be used for both logged-in customers and guest customers.
|
||||
|
||||
You can retrieve an order by its display ID using the [Look Up Order endpoint](https://docs.medusajs.com/api/store#orders_getorders):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.orders.lookupOrder({
|
||||
display_id: 1,
|
||||
email: "user@example.com",
|
||||
})
|
||||
.then(({ order }) => {
|
||||
console.log(order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useOrders } from "medusa-react"
|
||||
|
||||
const Order = () => {
|
||||
const {
|
||||
order,
|
||||
isLoading,
|
||||
} = useOrders({
|
||||
display_id: 1,
|
||||
email: "user@example.com",
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{order && <span>{order.display_id}</span>}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Order
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/orders?display_id=1&email=user@example.com`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires two query parameters:
|
||||
|
||||
- `display_id`: a string indicating display ID of the order. If you already have an order object, you can retrieve the display ID using `order.display_id`.
|
||||
- `email`: a string indicating the email associated with the order.
|
||||
|
||||
You can pass other query parameters to filter the orders even further, and the endpoint will return the first order that matches the filters. Learn more about available query parameters in the [API reference](https://docs.medusajs.com/api/store#orders_getorders).
|
||||
|
||||
The request returns the order as an object.
|
||||
|
||||
---
|
||||
|
||||
## Retrieve Order by Cart ID
|
||||
|
||||
In certain scenarios, you may need to retrieve an order’s details using the ID of the cart associated with the order. This can be useful when showing a success page after a cart is completed and an order is placed.
|
||||
|
||||
You can retrieve an order by the cart ID using the [Get by Cart ID endpoint](https://docs.medusajs.com/api/store#orders_getordersordercartid):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.orders.retrieveByCartId(cartId)
|
||||
.then(({ order }) => {
|
||||
console.log(order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useCartOrder } from "medusa-react"
|
||||
|
||||
const Order = () => {
|
||||
const {
|
||||
order,
|
||||
isLoading,
|
||||
} = useCartOrder(cartId)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{order && <span>{order.display_id}</span>}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Order
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/store/orders/cart/${cartId}`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order }) => {
|
||||
console.log(order.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the ID of the cart as a path parameter.
|
||||
|
||||
The request returns the order as an object.
|
||||
|
||||
---
|
||||
|
||||
## Retrieve a Customer’s Orders
|
||||
|
||||
When a customer is logged in, you can retrieve a list of their orders. This is typically useful to show a customer their orders in their profile. This method can only be used for logged-in customers.
|
||||
|
||||
You can learn how to retrieve a customer’s orders in the [How to Implement Customer Profiles](/modules/customers/storefront/implement-customer-profiles#retrieve-a-customers-orders) documentation.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to handle order edits in the storefront](./handle-order-edits.mdx)
|
||||
- [How to implement claim order flow in the storefront](./implement-claim-order.mdx)
|
||||
171
www/apps/docs/content/modules/orders/swaps.md
Normal file
171
www/apps/docs/content/modules/orders/swaps.md
Normal file
@@ -0,0 +1,171 @@
|
||||
---
|
||||
description: "Learn what swaps are, swap processes implemented in the Medusa backend, and a swap’s relation to other entities"
|
||||
---
|
||||
|
||||
# Swaps Architecture Overview
|
||||
|
||||
In this document, you’ll learn what swaps are, swap processes implemented in the Medusa backend, and a swap’s relation to other entities.
|
||||
|
||||
## Overview
|
||||
|
||||
After an order is created and fulfilled, the customer may need to replace an item they received with another. They can then create a swap, requesting to return an item they have in place for a new item. The swap, similar to an order, can then be paid, fulfilled, and more.
|
||||
|
||||
The Medusa core provides the necessary implementation and functionalities that allow you to integrate swaps in your store and automate the Return Merchandise Authorization (RMA) flow.
|
||||
|
||||
---
|
||||
|
||||
## Swap Entity Overview
|
||||
|
||||
Some of the attributes of the `Swap` entity include:
|
||||
|
||||
- `fulfillment_status`: a string indicating the status of the swap’s fulfillment. Its possible values indicated by the [SwapFulfillmentStatus enum](../../references/entities/enums/SwapFulfillmentStatus.md) can determine whether all items have been fulfilled, shipped, or canceled.
|
||||
- `payment_status`: a string indicating the status of the swap’s payment. Its possible values indicated by the [SwapPaymentStatus enum](../../references/entities/enums/SwapFulfillmentStatus.md) can determine whether the payment of the swap has been captured or refunded.
|
||||
- `difference_due`: An integer indicating the difference amount between the order’s original total and the new total imposed by the swap.
|
||||
- If the value of `difference_due` is negative, that means the customer should be refunded.
|
||||
- If it’s positive, that means the customer must authorize additional payment.
|
||||
- If it’s zero, then no refund or additional payment is required.
|
||||
- `confirmed_at`: A date indicating when the swap was confirmed by the customer.
|
||||
- `canceled_at`: A date indicating when the swap was canceled.
|
||||
- `no_notification`: a boolean value indicating whether the customer should receive notifications when the order is updated.
|
||||
- `allow_backorder`: a boolean value indicating whether a swap can be created and completed with items that are out of stock.
|
||||
|
||||
There are other important attributes discussed in later sections. Check out the full [Swap entity in the entities reference](../../references/entities/classes/Swap.md).
|
||||
|
||||
---
|
||||
|
||||
## How are Swaps Created
|
||||
|
||||
In Medusa, Swaps are created by the customer through the storefront. This ensures an automated Return Merchandise Authorization (RMA) flow. This section explains the ideal and recommended process, but you’re free in how you choose to implement Swaps creation flow.
|
||||
|
||||
### Idempotency Key
|
||||
|
||||
An Idempotency Key is a unique key associated with a swap. It is generated when the swap creation process is started and can be used to retry the swap creation safely if an error occurs. The idempotency key is stored in the `Swap` entity under the attribute `idempotency_key`.
|
||||
|
||||
Keep in mind that the idempotency key stored in the swap is only used when creating the swap. All operations related to the swap’s cart and its completion use the [cart’s idempotency key](../carts-and-checkout/cart.md#idempotency-key).
|
||||
|
||||
You can learn more about idempotency keys [here](../../development/idempotency-key/overview.mdx).
|
||||
|
||||
### Swap Creation Process
|
||||
|
||||
The customer starts by creating their swap, which can be done through the Create Swap endpoint. In this endpoint, the following steps are implemented:
|
||||
|
||||

|
||||
|
||||
1. The swap’s creation is initiated with the `SwapService`'s [create method](../../references/services/classes/SwapService.md#create):
|
||||
1. The order is first validated to see if a swap can be created. This includes checking the `payment_status` of the order to ensure the payment has already been captured, and the `fulfillment_status` of the order to ensure the status isn’t `not_fulfilled`. If any of these conditions aren’t met, the process is terminated with an error.
|
||||
2. The items that the customer chose to return are then validated. If any item has been previously canceled, meaning that its order, swap, or claim have been previously canceled, the process is terminated with an error.
|
||||
3. If all the conditions above are met, the swap is then created and associated with the order using the `order_id` attribute.
|
||||
4. A return is created and linked to the swap. The return’s items are set to the items that the customer chose to return.
|
||||
2. After the swap has been created, a cart is then created for the swap using the `SwapService`'s [createCart method](../../references/services/classes/SwapService.md#createcart). The cart is used to finalize the process of the swap creation process, but more on that later. The swap is associated with the cart using the `cart_id` attribute.
|
||||
3. The return associated with the swap is marked as fulfilled, as this is taken care of by the customer.
|
||||
|
||||
After the swap has been created, the customer should undergo a swap-completion process similar to the checkout process where they provide shipping and billing addresses, choose shipping and payment methods, authorize any additional payment required, then finally completing the cart.
|
||||
|
||||
This is all made possible since the swap is linked to a cart, so the same checkout flow can be implemented in a swap context. The cart completion strategy also handles the completion differently for swaps, as explained [here](../carts-and-checkout/cart.md#cart-completion).
|
||||
|
||||
---
|
||||
|
||||
## Handling Swap Payment
|
||||
|
||||
After the swap has been created and completed by the customer, the merchant can then process the payment of the swap. This includes either refunding or capturing an additional payment, which is decided by the value of the `difference_due` attribute as explained in the [Swap Entity section](#swap-entity-overview).
|
||||
|
||||
The processing of the swap’s payment can be done either using the `SwapService`'s [processDifference method](../../references/services/classes/SwapService.md#processdifference), or using the [Process Swap Payment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderswapsswapprocesspayment).
|
||||
|
||||
If the swap requires any additional payment, the customer is expected to have authorized the payment during the [swap and cart completion flow explained earlier](#how-are-swaps-created). The merchant can then capture the payment and the `payment_status` of the swap is set to `captured`.
|
||||
|
||||
If the swap requires a refund, the merchant can refund the payment to the customer and the `payment_status` of the swap is set to `difference_refunded`. The same status is used if no refund or additional payment are required.
|
||||
|
||||
If the capturing or refunding of the payment causes any errors, the payment status is changed to `requires_action`.
|
||||
|
||||
A swap’s payment can be accessed by expanding the `payment` relation and accessing `swap.payment`. A payment is represented by the `Payment` entity.
|
||||
|
||||
---
|
||||
|
||||
## Handling Swap Fulfillment
|
||||
|
||||
After the swap has been created and completed by the customer, the merchant should handle the [fulfillment](./fulfillments.md) of the new items.
|
||||
|
||||
Although you have freedom in how you implement the process, the recommended process provided in the Medusa backend is as follows:
|
||||
|
||||

|
||||
|
||||
1. The fulfillment is created either using the `SwapService`'s [createFulfillment method](../../references/services/classes/SwapService.md#createfulfillment) or using the [Create a Swap Fulfillment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderswapsswapfulfillments). This would set the `fulfillment_status` of the swap either to `fulfilled` if all items have been fulfilled, or `partially_fulfilled` if only some items were fulfilled.
|
||||
2. The shipment can then be created using the `SwapService`'s [createShipment method](../../references/services/classes/SwapService.md#createshipment) or using the [Create Swap Shipment endpoint](https://docs.medusajs.com/api/admin#orders_postordersorderswapsswapshipments). This would set the `fulfillment_status` of the swap either to `shipped` if all items have been shipped, or `partially_shipped` if only some items were shipped.
|
||||
3. Alternatively, a fulfillment can be canceled after it has been created using the `SwapService`'s [cancelFulfillment method](../../references/services/classes/SwapService.md#cancelfulfillment) or using the [Cancel Swap’s Fulfillment endpoint](https://docs.medusajs.com/api/admin#orders_postordersswapfulfillmentscancel). This would set the `fulfillment_status` of the swap to `canceled`.
|
||||
|
||||
A swap’s fulfillments can be accessed by expanding the `fulfillments` relation and accessing `swap.fulfillments`. A fulfillment is represented by the `Fulfillment` entity.
|
||||
|
||||
---
|
||||
|
||||
## Handling a Swap's Return
|
||||
|
||||
A swap's return can be marked as received, which would adjust the inventory and change the status of the return. This process is explained within the [Returns documentation](./returns.md#mark-return-as-received-process).
|
||||
|
||||
---
|
||||
|
||||
## Canceling a Swap
|
||||
|
||||
A swap can be canceled by the merchant if necessary. It can be done either through the `SwapService`'s [cancel method](../../references/services/classes/SwapService.md#cancel) or the [Cancel Swap endpoint](https://docs.medusajs.com/api/admin#orders_postordersswapcancel).
|
||||
|
||||
A swap can’t be canceled if:
|
||||
|
||||
- The payment has been refunded (the `payment_status` is either `difference_refunded`, `partially_refunded`, or `refunded`).
|
||||
- Its fulfillment isn’t canceled. You’ll have to cancel the swap’s fulfillment as explained in the [Handling Swap Fulfillment section](#handling-swap-fulfillment).
|
||||
- Its return isn’t canceled. You’ll have to [cancel the return](./returns.md#cancel-a-return) associated with the swap first before canceling the swap.
|
||||
|
||||
---
|
||||
|
||||
## RMA Automation with Swaps
|
||||
|
||||
Giving the client control over the creation of the swap and handling the returns allows businesses to automate their RMA flow.
|
||||
|
||||
The client, typically the customer, creates the swap, authorizes any additional payment required, and handles returning the item. The admin, typically the merchant, can view the created swap, process the payment, and fulfill and ship the additional items.
|
||||
|
||||

|
||||
|
||||
This removes any friction and support required between the client and the admin.
|
||||
|
||||
---
|
||||
|
||||
## Relation to Other Entities
|
||||
|
||||
This section includes relations that weren’t mentioned in other sections.
|
||||
|
||||
### Order
|
||||
|
||||
The swap must be associated with the [order](./orders.md) it’s created for. An order is represented by the `Order` entity.
|
||||
|
||||
You can access the order’s ID using the `order_id` attribute. You can also access the order by expanding the `order` relation and accessing `swap.order`.
|
||||
|
||||
### Cart
|
||||
|
||||
The swap must be associated with a [cart](../carts-and-checkout/cart.md). A cart is represented by the `Cart` entity.
|
||||
|
||||
You can access the cart’s ID using the `cart_id` attribute. You can also access the cart by expanding the `cart` relation and accessing `swap.cart`.
|
||||
|
||||
### LineItem
|
||||
|
||||
The swap is associated with new items that should replace the customer’s items. These items are represented by the `LineItem` entity.
|
||||
|
||||
You can access the swap’s new items by expanding the `additional_items` relation and accessing `swap.additional_items`.
|
||||
|
||||
### Return
|
||||
|
||||
The swap is associated with a [return](./returns.md) that is created when the swap is created. A return is represented by the `Return` entity.
|
||||
|
||||
You can access the swap’s return by expanding the `return_order` relation and accessing `swap.return_order`.
|
||||
|
||||
### Address
|
||||
|
||||
The swap can be associated with shipping and billing addresses. Both shipping and billing addresses are represented by the `Address` entity.
|
||||
|
||||
You can access the swap’s billing address ID using the `billing_address_id` property. You can also access the billing address by expanding the `billing_address` relation and accessing `swap.billing_address`.
|
||||
|
||||
You can access the swap’s shipping address ID using the `shipping_address_id` property. You can also access the shipping address by expanding the `shipping_address` relation and accessing `swap.shipping_address`.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage swaps](./admin/manage-swaps.mdx)
|
||||
- [Order Architecture Overview](./orders.md)
|
||||
Reference in New Issue
Block a user