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.
You can check out how to implement order editing using the Admin APIs in this documentation.
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.
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 to get started.
It is also assumed you already have a storefront set up. It can be a custom storefront or one of Medusa’s storefronts. If you don’t have a storefront set up, you can install the Next.js Starter Template.
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 and have created an instance of the client.
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 and have used MedusaProvider higher in your component tree.
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 Route:
import { useOrderEdit } from "medusa-react"
type Props = {
orderEditId: string
}
const OrderEdit = ({ orderEditId }: Props) => {
const { order_edit, isLoading } = useOrderEdit(orderEditId)
return (
<div>
{isLoading && <span>Loading...</span>}
{order_edit && (
<ul>
{order_edit.changes.map((change) => (
<li key={change.id}>{change.type}</li>
))}
</ul>
)}
</div>
)
}
export default OrderEdit
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.
You can learn more about what fields to expect in the API reference.
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:
type
can be either:
item_add
: In this case, a new item is being added.line_item
will be an item object andoriginal_line_item
will benull
.item_update
: In this case, an item’s quantity in the original order is updated.line_item
will be the updated item, andoriginal_line_item
will be the item in the original order. You can either just useline_item
to show the new quantity, or show the customer a comparison between the old and new quantity usingoriginal_line_item
as well.item_remove
: In this case, an item in the original order is removed. Theoriginal_line_item
will be the item in the original order, andline_item
will benull
.
Here’s an example of how you can use this data to show the customer the requested edits to the order:
<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.
Make Additional Payments
This section explains how to authorize the payment using one payment processor and payment session. However, payment collections allow customers to pay in installments or with more than one provider. You can learn more about how to do that using the batch routes of the Payment APIs
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:
- Show the customer the available payment processors. These can be retrieved from the details of the region of the order.
- When the customer selects the payment processor, initialize the payment session of that provider in the payment collection. You can do that by sending a request to the Manage Payment Sessions API Route, passing it the payment collection’s ID as a path parameter, and the payment processor's ID as a request body parameter:
import { useManagePaymentSession } from "medusa-react"
type Props = {
paymentCollectionId: string
}
const OrderEditPayment = ({
paymentCollectionId
}: Props) => {
const managePaymentSession = useManagePaymentSession(
paymentCollectionId
)
// ...
const handleAdditionalPayment = (provider_id: string) => {
managePaymentSession.mutate({
provider_id,
}, {
onSuccess: ({ payment_collection }) => {
console.log(payment_collection.payment_sessions)
}
})
}
// ...
}
export default OrderEditPayment
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)
})
- 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. - Authorize the payment using the payment processor. The Authorize Payment Session API Route accepts the payment collection’s ID and the ID of the payment session as path parameters:
import { useAuthorizePaymentSession } from "medusa-react"
type Props = {
paymentCollectionId: string
}
const OrderEditPayment = ({
paymentCollectionId
}: Props) => {
const authorizePaymentSession = useAuthorizePaymentSession(
paymentCollectionId
)
// ...
const handleAuthorizePayment = (paymentSessionId: string) => {
authorizePaymentSession.mutate(paymentSessionId, {
onSuccess: ({ payment_collection }) => {
console.log(payment_collection.payment_sessions)
}
})
}
// ...
}
export default OrderEditPayment
After performing the above steps, you can complete the Order Edit.
Complete the Order Edit
To confirm and complete the order edit, send a request to the Complete Order Edit API Route:
import { useCompleteOrderEdit } from "medusa-react"
type Props = {
orderEditId: string
}
const OrderEdit = ({ orderEditId }: Props) => {
const completeOrderEdit = useCompleteOrderEdit(
orderEditId
)
// ...
const handleCompleteOrderEdit = () => {
completeOrderEdit.mutate(void 0, {
onSuccess: ({ order_edit }) => {
console.log(order_edit.confirmed_at)
}
})
}
// ...
}
export default OrderEdit
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.
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 API Route:
import { useDeclineOrderEdit } from "medusa-react"
type Props = {
orderEditId: string
}
const OrderEdit = ({ orderEditId }: Props) => {
const declineOrderEdit = useDeclineOrderEdit(orderEditId)
// ...
const handleDeclineOrderEdit = (
declinedReason: string
) => {
declineOrderEdit.mutate({
declined_reason: declinedReason,
}, {
onSuccess: ({ order_edit }) => {
console.log(order_edit.declined_at)
}
})
}
// ...
}
export default OrderEdit
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)
})
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.