docs: publish restructure (#3496)
* docs: added features and guides overview page * added image * added version 2 * added version 3 * added version 4 * docs: implemented new color scheme * docs: redesigned sidebar (#3193) * docs: redesigned navbar for restructure (#3199) * docs: redesigned footer (#3209) * docs: redesigned cards (#3230) * docs: redesigned admonitions (#3231) * docs: redesign announcement bar (#3236) * docs: redesigned large cards (#3239) * docs: redesigned code blocks (#3253) * docs: redesigned search modal and page (#3264) * docs: redesigned doc footer (#3268) * docs: added new sidebars + refactored css and assets (#3279) * docs: redesigned api reference sidebar * docs: refactored css * docs: added code tabs transition * docs: added new sidebars * removed unused assets * remove unusued assets * Fix deploy errors * fix incorrect link * docs: fixed code responsivity + missing icons (#3283) * docs: changed icons (#3296) * docs: design fixes to the sidebar (#3297) * redesign fixes * docs: small design fixes * docs: several design fixes after restructure (#3299) * docs: bordered icon fixes * docs: desgin fixes * fixes to code blocks and sidebar scroll * design adjustments * docs: restructured homepage (#3305) * docs: restructured homepage * design fixes * fixed core concepts icon * docs: added core concepts page (#3318) * docs: restructured homepage * design fixes * docs: added core concepts page * changed text of different components * docs: added architecture link * added missing prop for user guide * docs: added regions overview page (#3327) * docs: added regions overview * moved region pages to new structure * docs: fixed description of regions architecture page * small changes * small fix * docs: added customers overview page (#3331) * docs: added regions overview * moved region pages to new structure * docs: fixed description of regions architecture page * small changes * small fix * docs: added customers overview page * fix link * resolve link issues * docs: updated regions architecture image * docs: second-iteration fixes (#3347) * docs: redesigned document * design fixes * docs: added products overview page (#3354) * docs: added carts overview page (#3363) * docs: added orders overview (#3364) * docs: added orders overview * added links in overview * docs: added vercel redirects * docs: added soon badge for cards (#3389) * docs: resolved feedback changes + organized troubleshooting pages (#3409) * docs: resolved feedback changes * added extra line * docs: changed icons for restructure (#3421) * docs: added taxes overview page (#3422) * docs: added taxes overview page * docs: fix sidebar label * added link to taxes overview page * fixed link * docs: fixed sidebar scroll (#3429) * docs: added discounts overview (#3432) * docs: added discounts overview * fixed links * docs: added gift cards overview (#3433) * docs: added price lists overview page (#3440) * docs: added price lists overview page * fixed links * docs: added sales channels overview page (#3441) * docs: added sales overview page * fixed links * docs: added users overview (#3443) * docs: fixed sidebar border height (#3444) * docs: fixed sidebar border height * fixed svg markup * docs: added possible solutions to feedback component (#3449) * docs: added several overview pages + restructured files (#3463) * docs: added several overview pages * fixed links * docs: added feature flags + PAK overview pages (#3464) * docs: added feature flags + PAK overview pages * fixed links * fix link * fix link * fixed links colors * docs: added strategies overview page (#3468) * docs: automated upgrade guide (#3470) * docs: automated upgrade guide * fixed vercel redirect * docs: restructured files in docs codebase (#3475) * docs: restructured files * docs: fixed eslint exception * docs: finished restructure loose-ends (#3493) * fixed uses of backend * docs: finished loose ends * eslint fixes * fixed links * merged master * added update instructions for v1.7.12
This commit is contained in:
842
docs/content/modules/orders/admin/edit-order.mdx
Normal file
842
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](/api/admin/#tag/OrderEdit).
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 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.md) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.md#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](/api/admin/#section/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](/api/admin/#tag/OrderEdit/operation/PostOrderEdits) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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](/api/admin/#tag/OrderEdit/operation/PostOrderEditsEditLineItems) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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](/api/admin/#tag/OrderEdit/operation/PostOrderEditsEditLineItemsLineItem) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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](/api/admin/#tag/OrderEdit/operation/DeleteOrderEditsOrderEditLineItemsLineItem) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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](/api/admin/#tag/OrderEdit/operation/DeleteOrderEditsOrderEditItemChange) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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](/api/admin/#tag/OrderEdit/operation/PostOrderEditsOrderEditRequest) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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](/api/admin/#tag/OrderEdit/operation/PostOrderEditsOrderEditConfirm) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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](/api/admin/#tag/Payment/operation/PostPaymentsPaymentCapture) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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](/api/admin/#tag/Payment/operation/PostPaymentsPaymentRefunds) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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](/api/admin/#tag/Payment/operation/PostPaymentsPaymentRefunds).
|
||||
|
||||
:::
|
||||
|
||||
It returns in the response the full Refund object.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Handle order edits on the storefront](../storefront/handle-order-edits.mdx)
|
||||
208
docs/content/modules/orders/backend/handle-order-claim-event.md
Normal file
208
docs/content/modules/orders/backend/handle-order-claim-event.md
Normal file
@@ -0,0 +1,208 @@
|
||||
---
|
||||
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.
|
||||
|
||||
### Redis
|
||||
|
||||
Redis is required for batch jobs to work. Make sure you [install Redis](../../../development/backend/prepare-environment.mdx#redis) and [configure it with the Medusa backend](../../../development/backend/configurations.md#redis).
|
||||
|
||||
### 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,
|
||||
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)
|
||||
357
docs/content/modules/orders/overview.mdx
Normal file
357
docs/content/modules/orders/overview.mdx
Normal file
@@ -0,0 +1,357 @@
|
||||
---
|
||||
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: '#',
|
||||
label: 'Admin: Manage Orders',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage orders using Admin APIs.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
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: '#',
|
||||
label: 'Storefront: Manage Customer Orders',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage orders as a customer.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
### 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: '#',
|
||||
label: 'Admin: Manage Draft Orders',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage draft orders using Admin APIs.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
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: '/api/admin#tag/Draft-Order',
|
||||
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: '#',
|
||||
label: 'Admin: Manage Returns',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage returns using Admin APIs.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Admin: Manage Swaps',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage swaps using Admin APIs.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Admin: Manage Claims',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage claims using Admin APIs.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
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: '#',
|
||||
label: 'Storefront: Create a Return',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a return as a customer.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Storefront: Create a Swap',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a swap as a customer.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/api/store#tag/Return',
|
||||
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: '#',
|
||||
label: 'Architecture: Order',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Order architecture.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Architecture: Swap',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Swap architecture.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Architecture: Return',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Return architecture.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Architecture: Claim',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Claim architecture.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Architecture: Draft Order',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Draft Order architecture.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Architecture: Fulfillment',
|
||||
customProps: {
|
||||
icon: Icons['circle-stack-solid'],
|
||||
description: 'Learn about the Fulfillment architecture.',
|
||||
isSoon: true,
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## 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.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
477
docs/content/modules/orders/storefront/handle-order-edits.mdx
Normal file
477
docs/content/modules/orders/storefront/handle-order-edits.mdx
Normal file
@@ -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 either the [Next.js](../../../starters/nextjs-medusa-starter.mdx) or [Gatsby](../../../starters/gatsby-medusa-starter.mdx) storefronts.
|
||||
|
||||
### 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.md) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.md#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](/api/store/#tag/OrderEdit/operation/GetOrderEditsOrderEdit) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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">
|
||||
|
||||
```ts
|
||||
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](/api/store/#tag/OrderEdit/operation/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 provider 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](/api/store/#tag/Payment/operation/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 providers. These can be retrieved from the details of [the region of the order](/api/store/#tag/Region/operation/GetRegionsRegion).
|
||||
2. When the customer selects the payment provider, initialize the payment session of that provider in the payment collection. You can do that by sending a request to the [Manage Payment Sessions](/api/store/#tag/Payment/operation/PostPaymentCollectionsSessions) endpoint, passing it the payment collection’s ID as a path parameter, and the payment provider’s ID as a request body parameter:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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">
|
||||
|
||||
```ts
|
||||
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 provider. The [Authorize Payment Session](/api/store/#tag/Payment/operation/PostPaymentCollectionsSessionsSessionAuthorize) endpoint accepts the payment collection’s ID and the ID of the payment session as path parameters:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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">
|
||||
|
||||
```ts
|
||||
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](/api/store/#tag/OrderEdit/operation/PostOrderEditsOrderEditComplete) endpoint:
|
||||
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs">
|
||||
<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">
|
||||
|
||||
```ts
|
||||
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" wrapperClassName="code-tabs">
|
||||
<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">
|
||||
|
||||
```ts
|
||||
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)
|
||||
210
docs/content/modules/orders/storefront/implement-claim-order.mdx
Normal file
210
docs/content/modules/orders/storefront/implement-claim-order.mdx
Normal file
@@ -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 either the [Next.js](../../../starters/nextjs-medusa-starter.mdx) or [Gatsby](../../../starters/gatsby-medusa-starter.mdx) storefronts.
|
||||
|
||||
### 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.md) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.md#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](/api/store/#tag/Auth/operation/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" wrapperClassName="code-tabs">
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.orders.claimOrders({
|
||||
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" wrapperClassName="code-tabs">
|
||||
<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)
|
||||
Reference in New Issue
Block a user