Files
medusa-store/docs/content/advanced/storefront/handle-order-edits.mdx
Shahed Nasser a248bf6e4f docs: added medusa-react snippets in how-to guides (#3091)
* added medusa-react snippets

* added more code snippets

* added medusa-react snippets

* docs: added medusa-react snippets to storefront how-to

* docs: added medusa-react snippets in admin how-to

* docs: fixed incorrect link
2023-01-23 21:04:09 +02:00

455 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# How to Handle an Order Edit
In this document, youll 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/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.mdx) to get started.
It is also assumed you already have a storefront set up. It can be a custom storefront or one of Medusas storefronts. If you dont 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 server using Medusas JS Client and JavaScripts Fetch API.
If you follow the JS Client code blocks, its assumed you already have [Medusas 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 server 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(`<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 edits 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 orders 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 items 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`.
Heres 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 collections ID as a path parameter, and the payment providers 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="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">
```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 sessions provider. For example, if the provider ID of a payment session is `stripe`, you must show Stripes card component to enter the customers card details.
2. Authorize the payment using the payment provider. The [Authorize Payment Session](/api/store/#tag/Payment/operation/PostPaymentCollectionsSessionsSessionAuthorize) endpoint accepts the payment collections 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">
```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="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">
```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 edits 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 isnt 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(`<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 edits ID as a path parameter.
In the request body parameters, you can optionally pass the `decline_reason` parameter. Its 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
- [Order Edit API reference](/api/store/#tag/OrderEdit)
- [Edit an order using Admin APIs](../admin/order-edit.mdx)