docs: added order edit documentation pages (#2885)
This commit is contained in:
611
docs/content/advanced/admin/order-edit.mdx
Normal file
611
docs/content/advanced/admin/order-edit.mdx
Normal file
@@ -0,0 +1,611 @@
|
||||
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.
|
||||
|
||||
:::note
|
||||
|
||||
The Order Editing feature is currently in beta mode and guarded by a feature flag. To use Order Editing either:
|
||||
|
||||
1. Enable the `MEDUSA_FF_ORDER_EDITING` environment variable;
|
||||
2. Or enable the `order_editing` key in the Medusa server's settings.
|
||||
|
||||
You can learn more about enabling it in the [feature flags](../backend/feature-flags/toggle.md) documentation.
|
||||
|
||||
:::
|
||||
|
||||
## 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 server installed and set up. If not, you can follow our [quickstart guide](../../quickstart/quick-start.md) to get started.
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa server using Medusa’s JS Client, JavaScript’s Fetch API, or cURL.
|
||||
|
||||
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).
|
||||
|
||||
### 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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/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 '<SERVER_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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/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 '<SERVER_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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/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 '<SERVER_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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/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 '<SERVER_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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/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 '<SERVER_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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/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 '<SERVER_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](../backend/subscribers/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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/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 '<SERVER_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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/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 '<SERVER_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
|
||||
medusa.admin.payments.refundPayment(paymentId, {
|
||||
amount
|
||||
})
|
||||
.then(({ refund }) => {
|
||||
console.log(refund.id);
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/payments/${paymentId}/refund`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
amount
|
||||
})
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ refund }) => {
|
||||
console.log(refund.id);
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<SERVER_URL>/admin/payments/<PAYMENT_ID>/refund' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"amount": 1000
|
||||
}'
|
||||
```
|
||||
|
||||
</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.
|
||||
|
||||
:::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.
|
||||
|
||||
## What’s Next
|
||||
|
||||
- Learn how to [handle order edits on the storefront](../storefront/handle-order-edits).
|
||||
- Check out more [order edit endpoints in the API reference](/api/admin/#tag/OrderEdit).
|
||||
326
docs/content/advanced/storefront/handle-order-edits.mdx
Normal file
326
docs/content/advanced/storefront/handle-order-edits.mdx
Normal file
@@ -0,0 +1,326 @@
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Handle an Order Edit
|
||||
|
||||
In this document, you’ll learn how to allow a customer to confirm or decline an Order Edit.
|
||||
|
||||
:::note
|
||||
|
||||
The Order Editing feature is currently in beta mode and guarded by a feature flag. To use Order Editing either:
|
||||
|
||||
1. Enable the `MEDUSA_FF_ORDER_EDITING` environment variable;
|
||||
2. Or enable the `order_editing` key in the Medusa server's settings.
|
||||
|
||||
You can learn more about enabling it in the [feature flags](../backend/feature-flags/toggle.md) documentation.
|
||||
|
||||
:::
|
||||
|
||||
## 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/order-edit.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 server installed and set up. If not, you can follow our [quickstart guide](../../quickstart/quick-start.md) 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.md) or [Gatsby](../../starters/gatsby-medusa-starter.md) storefronts.
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa server 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).
|
||||
|
||||
### 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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_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:
|
||||
|
||||
```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:
|
||||
|
||||
```jsx
|
||||
<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>
|
||||
|
||||
```ts
|
||||
medusa.paymentCollections.managePaymentSession(paymentCollectionId, {
|
||||
provider_id
|
||||
})
|
||||
.then(({ payment_collection }) => {
|
||||
console.log(payment_collection.payment_sessions);
|
||||
});
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_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="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_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.
|
||||
|
||||
## What’s Next
|
||||
|
||||
- Learn [how to edit an order using Admin APIs](../admin/order-edit.mdx)
|
||||
- Learn more about [order edit endpoints in the API reference](/api/store/#tag/OrderEdit)
|
||||
@@ -267,6 +267,11 @@ module.exports = {
|
||||
id: "advanced/storefront/implement-claim-order",
|
||||
label: "Implement Claim Order"
|
||||
},
|
||||
{
|
||||
type: "doc",
|
||||
id: "advanced/storefront/handle-order-edits",
|
||||
label: "Handle Order Edits"
|
||||
},
|
||||
{
|
||||
type: "doc",
|
||||
id: "advanced/storefront/use-sales-channels",
|
||||
@@ -313,6 +318,11 @@ module.exports = {
|
||||
id: "advanced/admin/manage-discounts",
|
||||
label: "Use Discount APIs"
|
||||
},
|
||||
{
|
||||
type: "doc",
|
||||
id: "advanced/admin/order-edit",
|
||||
label: "Edit an Order"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user