From 7e5df1307266a7ded6cf777bc12db6b32f66efd7 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 26 Apr 2023 11:05:22 +0300 Subject: [PATCH] docs: added how to manage orders guide (#3891) * docs: added how to manage orders guide * eslint fixes * fix indentation --- .../modules/orders/admin/manage-orders.mdx | 1171 +++++++++++++++++ docs/content/modules/orders/overview.mdx | 3 +- www/docs/sidebars.js | 7 +- 3 files changed, 1174 insertions(+), 7 deletions(-) create mode 100644 docs/content/modules/orders/admin/manage-orders.mdx diff --git a/docs/content/modules/orders/admin/manage-orders.mdx b/docs/content/modules/orders/admin/manage-orders.mdx new file mode 100644 index 0000000000..260a804d7b --- /dev/null +++ b/docs/content/modules/orders/admin/manage-orders.mdx @@ -0,0 +1,1171 @@ +--- +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 Manage Orders + +In this document, you’ll learn how to manage orders using the admin REST APIs. + +## Overview + +Using the order’s admin REST APIs, you can manage and process the orders in your commerce store. + +### Scenario + +You want to add or use the following admin functionalities: + +- List and filter orders. +- Update the order’s details. +- Manage an order’s payment. This includes capturing and refunding an order. +- Manage an order’s fulfillment. That includes creating the fulfillment, canceling it, and creating a shipment for the fulfillment. +- Manage an order’s status, including completing, canceling, and archiving an order. + +:::note + +There are many more functionalities within the order domain related to returns, swaps, claims, and more. Each of these functionalities are explained in their own pages. + +::: + +--- + +## 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). + +--- + +## List Orders + +You can list orders by sending a request to the [List Orders endpoint](/api/admin#tag/Orders/operation/GetOrders): + + + + +```ts +medusa.admin.orders.list() +.then(({ orders, limit, offset, count }) => { + console.log(orders.length) +}) +``` + + + + +```tsx +import { useAdminOrders } from "medusa-react" + +const Orders = () => { + const { orders, isLoading } = useAdminOrders() + + return ( +
+ {isLoading && Loading...} + {orders && !orders.length && No Orders} + {orders && orders.length > 0 && ( +
    + {orders.map((order) => ( +
  • {order.display_id}
  • + ))} +
+ )} +
+ ) +} + +export default Orders +``` + +
+ + +```ts +fetch(`/admin/orders`, { + credentials: "include", +}) +.then((response) => response.json()) +.then(({ orders, limit, offset, count }) => { + console.log(orders.length) +}) +``` + + + + +```bash +curl -L -X GET '/admin/orders' \ +-H 'Authorization: Bearer ' +``` + + +
+ +This endpoint does not require any path parameters. You can pass it query parameters to filter the orders received. + +The request returns an array of orders along with [pagination fields](/api/admin#section/Pagination). + +### Filter Orders + +This endpoint accepts a variety of query parameters that allow you to filter orders. You can check available query parameters in the [API reference](/api/admin#tag/Orders/operation/GetOrders). + +For example, you can filter the orders by one or more status: + + + + +```ts +medusa.admin.orders.list({ + status: ["completed"], + // the JS client requires these fields + // to be passed + offset, + limit, +}) +.then(({ orders, limit, offset, count }) => { + console.log(orders.length) +}) +``` + + + + +```tsx +import { useAdminOrders } from "medusa-react" + +const Orders = () => { + const { orders, isLoading } = useAdminOrders({ + status: ["completed"], + // the JS client requires these fields + // to be passed + offset, + limit, + }) + + return ( +
+ {isLoading && Loading...} + {orders && !orders.length && No Orders} + {orders && orders.length > 0 && ( +
    + {orders.map((order) => ( +
  • {order.display_id}
  • + ))} +
+ )} +
+ ) +} + +export default Orders +``` + +
+ + +```ts +fetch(`/admin/orders?status[]=completed`, { + credentials: "include", +}) +.then((response) => response.json()) +.then(({ orders, limit, offset, count }) => { + console.log(orders.length) +}) +``` + + + + +```bash +curl -L -X GET '/admin/orders?status[]=completed' \ +-H 'Authorization: Bearer ' +``` + + +
+ +:::note + +You can check available order statuses [here](../../../references/entities/enums/OrderStatus). + +::: + +Another example is filtering the orders by a sales channel: + + + + +```ts +medusa.admin.orders.list({ + sales_channel_id: [ + salesChannelId, + ], + // the JS client requires these fields + // to be passed + offset, + limit, +}) +.then(({ orders, limit, offset, count }) => { + console.log(orders.length) +}) +``` + + + + +```tsx +import { useAdminOrders } from "medusa-react" + +const Orders = () => { + const { orders, isLoading } = useAdminOrders({ + sales_channel_id: [ + salesChannelId, + ], + // the JS client requires these fields + // to be passed + offset, + limit, + }) + + return ( +
+ {isLoading && Loading...} + {orders && !orders.length && No Orders} + {orders && orders.length > 0 && ( +
    + {orders.map((order) => ( +
  • {order.display_id}
  • + ))} +
+ )} +
+ ) +} + +export default Orders +``` + +
+ + + + +```ts +fetch(`/admin/orders?sales_channel_id[]=${salesChannelId}`, { + credentials: "include", +}) +.then((response) => response.json()) +.then(({ orders, limit, offset, count }) => { + console.log(orders.length) +}) +``` + + + + +```bash +curl -L -X GET '/admin/orders?sales_channel_id[]=' \ +-H 'Authorization: Bearer ' +``` + + +
+ +You can also combine filters together: + + + + +```ts +medusa.admin.orders.list({ + status: ["completed"], + sales_channel_id: [ + salesChannelId, + ], + // the JS client requires these fields + // to be passed + offset, + limit, +}) +.then(({ orders, limit, offset, count }) => { + console.log(orders.length) +}) +``` + + + + +```tsx +import { useAdminOrders } from "medusa-react" + +const Orders = () => { + const { orders, isLoading } = useAdminOrders({ + status: ["completed"], + sales_channel_id: [ + salesChannelId, + ], + // the JS client requires these fields + // to be passed + offset, + limit, + }) + + return ( +
+ {isLoading && Loading...} + {orders && !orders.length && No Orders} + {orders && orders.length > 0 && ( +
    + {orders.map((order) => ( +
  • {order.display_id}
  • + ))} +
+ )} +
+ ) +} + +export default Orders +``` + +
+ + + + +```ts +fetch(`/admin/orders?status[]=completed&sales_channel_id[]=${salesChannelId}`, { + credentials: "include", +}) +.then((response) => response.json()) +.then(({ orders, limit, offset, count }) => { + console.log(orders.length) +}) +``` + + + + +```bash +curl -L -X GET '/admin/orders?status[]=completed&sales_channel_id[]=' \ +-H 'Authorization: Bearer ' +``` + + +
+ +--- + +## Retrieve an Order + +You can retrieve an order by sending a request to the [Get an Order endpoint](/api/admin#tag/Orders/operation/GetOrdersOrder): + + + + +```ts +medusa.admin.orders.retrieve(orderId) +.then(({ order }) => { + console.log(order.id) +}) +``` + + + + +```tsx +import { useAdminOrder } from "medusa-react" + +const Order = () => { + const { + order, + isLoading, + } = useAdminOrder(orderId) + + return ( +
+ {isLoading && Loading...} + {order && {order.display_id}} + +
+ ) +} + +export default Order +``` + +
+ + +```ts +fetch(`/admin/orders/${orderId}`, { + credentials: "include", +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.id) +}) +``` + + + + +```bash +curl -L -X GET '/admin/orders/' \ +-H 'Authorization: Bearer ' +``` + + +
+ +This endpoint requires the order ID to be passed as a path parameter. + +The request returns the full order as an object. + +--- + +## Update an Order’s Details + +Updating an order’s details can include updating its: + +- Email +- Shipping address +- Billing address +- Add new items (this would not invoke the same process and operations as order edits. This would only create the items and attach them to the order). +- Region +- Discounts +- Customer ID +- Payment Method +- Shipping Method +- `no_notification` property + +You can update any of the above details of an order by sending a request to the [Update an Order endpoint](/api/admin#tag/Orders/operation/PostOrdersOrder): + + + + +```ts +medusa.admin.orders.update(orderId, { + email, +}) +.then(({ order }) => { + console.log(order.id) +}) +``` + + + + +```tsx +import { useAdminUpdateOrder } from "medusa-react" + +const UpdateOrder = () => { + const updateOrder = useAdminUpdateOrder( + orderId + ) + // ... + + const handleUpdate = () => { + updateOrder.mutate({ + email, + }) + } + + // ... +} + +export default UpdateOrder +``` + + + + +```ts +fetch(`/admin/orders/${orderId}`, { + credentials: "include", + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email, + }), +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.id) +}) +``` + + + + +```bash +curl -L -X POST '/admin/orders/' \ +-H 'Authorization: Bearer ' \ +-H 'Content-Type: application/json' \ +--data-raw '{ + "email": "user@example.com" +}' +``` + + + + +This endpoint requires the order’s ID to be passed as a path parameter. + +In the request body parameters, you can pass any of the order’s fields mentioned earlier that you want to update. In the example above, you edit the email associated with the order. You can learn about other available request body parameters in the [API reference](/api/admin#tag/Orders/operation/PostOrdersOrder). + +The request returns the updated order as an object. + +--- + +## Manage an Order’s Payment + +### Capture an Order’s Payment + +You can capture an order’s payment by sending a request to the [Capture Order’s Payment endpoint](/api/admin#tag/Orders/operation/PostOrdersOrderCapture): + + + + +```ts +medusa.admin.orders.capturePayment(orderId) +.then(({ order }) => { + console.log(order.payment_status) +}) +``` + + + + +```tsx +import { useAdminCapturePayment } from "medusa-react" + +const CapturePayment = () => { + const capturePament = useAdminCapturePayment( + orderId + ) + // ... + + const handleCapture = () => { + capturePament.mutate() + } + + // ... +} + +export default CapturePayment +``` + + + + + +```ts +fetch(`/admin/orders/${orderId}/capture`, { + credentials: "include", + method: "POST", +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.payment_status) +}) +``` + + + + +```bash +curl -L -X POST '/admin/orders//capture' \ +-H 'Authorization: Bearer ' +``` + + + + +This endpoint requires the Order ID as a path parameter. + +The request returns the updated order as an object. + +### Refund Payment + +You can refund an amount that is less than `order.refundable_amount`. + +To refund payment, send a request to the [Refund Payment endpoint](/api/admin#tag/Orders/operation/PostOrdersOrderRefunds): + + + + +```ts +medusa.admin.orders.refundPayment(orderId, { + amount, + reason, +}) +.then(({ order }) => { + console.log(order.payment_status, order.refunded_total) +}) +``` + + + + +```tsx +import { useAdminRefundPayment } from "medusa-react" + +const RefundPayment = () => { + const refundPayment = useAdminRefundPayment( + orderId + ) + // ... + + const handleRefund = () => { + refundPayment.mutate({ + amount, + reason, + }) + } + + // ... +} + +export default RefundPayment +``` + + + + +```ts +fetch(`/admin/orders/${orderId}/refund`, { + credentials: "include", + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + amount, + reason, + }), +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.payment_status, order.refunded_total) +}) +``` + + + + +```bash +curl -L -X POST '/admin/orders//refund' \ +-H 'Authorization: Bearer ' \ +-H 'Content-Type: application/json' \ +--data-raw '{ + "amount": 1000, + "reason": "customer did not like the order" +}' +``` + + + + +This endpoint requires the order’s ID to be passed as a path parameter. + +The following parameters are required in the request body parameters: + +- `amount`: a number indicating the amount to refund. +- `reason`: a string indicating why the refund is being issued. + +You can also add other optional body parameters, as explained in the [API reference](/api/admin#tag/Orders/operation/PostOrdersOrderRefunds). + +The request returns the updated order as an object. + +--- + +## Manage Order Fulfillments + +### Create a Fulfillment + +You can create a fulfillment by sending a request to the [Create a Fulfillment endpoint](/api/admin#tag/Orders/operation/PostOrdersOrderFulfillments): + + + + +```ts +medusa.admin.orders.createFulfillment(orderId, { + items: [ + { + itemId, + quantity, + }, + ], +}) +.then(({ order }) => { + console.log(order.fulfillment_status, order.fulfillments) +}) +``` + + + + +```tsx +import { useAdminCreateFulfillment } from "medusa-react" + +const CreateFuilfillment = () => { + const createFulfillment = useAdminCreateFulfillment( + orderId + ) + // ... + + const handleCreate = () => { + createFulfillment.mutate({ + items: [ + { + itemId, + quantity, + }, + ], + }) + } + + // ... +} + +export default CreateFuilfillment +``` + + + + +```ts +fetch(`/admin/orders/${orderId}/fulfillment`, { + credentials: "include", + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + items: [ + { + itemId, + quantity, + }, + ], + }), +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.fulfillment_status, order.fulfillments) +}) +``` + + + + +```bash +curl -L -X POST '/admin/orders//fulfillment' \ +-H 'Authorization: Bearer ' \ +-H 'Content-Type: application/json' \ +--data-raw '{ + "items": [ + { + "item_id": "", + "quantity": 1 + } + ] +}' +``` + + + + +This endpoint requires the order’s ID to be passed as a path parameter. + +In the request body, the `items` parameter is required. It’s an array of objects that are the items to fulfill. You can fulfill all items in the order or some items. + +Each object in the array must have the following properties: + +- `item_id`: a string indicating the ID of the item to fulfill. +- `quantity`: a number indicating the quantity to fulfill. + +You can also pass other optional request body parameters as explained in the [API reference](/api/admin#tag/Orders/operation/PostOrdersOrderFulfillments). + +The request returns the updated order as an object. + +### Create Shipment + +You can create a shipment for a fulfillment by sending a request to the [Create Shipment endpoint](/api/admin#tag/Orders/operation/PostOrdersOrderShipment): + + + + +```ts +medusa.admin.orders.createShipment(orderId, { + fulfillment_id, +}) +.then(({ order }) => { + console.log(order.fulfillment_status, order.fulfillments) +}) +``` + + + + +```tsx +import { useAdminCreateShipment } from "medusa-react" + +const CreateShipment = () => { + const createShipment = useAdminCreateShipment( + orderId + ) + // ... + + const handleCreate = () => { + createShipment.mutate({ + fulfillment_id, + }) + } + + // ... +} + +export default CreateShipment +``` + + + + +```ts +fetch(`/admin/orders/${orderId}/shipment`, { + credentials: "include", + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + fulfillment_id, + }), +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.fulfillment_status, order.fulfillments) +}) +``` + + + + +```bash +curl -L -X POST '/admin/orders//shipment' \ +-H 'Authorization: Bearer ' \ +-H 'Content-Type: application/json' \ +--data-raw '{ + "fulfillment_id": "" +}' +``` + + + + +This endpoint requires passing the order’s ID as a path parameter. + +In the request body, the `fulfillment_id` parameter is required. Its value is the ID of the fulfillment to create the shipment for. You can also pass other optional body parameters as explained in the [API reference](/api/admin#tag/Orders/operation/PostOrdersOrderShipment). + +The request returns the updated order as an object. + +### Cancel Fulfillment + +You can cancel a fulfillment by sending a request to the [Cancel Fulfillment endpoint](/api/admin#tag/Orders/operation/PostOrdersOrderFulfillmentsCancel): + + + + +```ts +medusa.admin.orders.cancelFulfillment(orderId, fulfillmentId) +.then(({ order }) => { + console.log(order.fulfillment_status) +}) +``` + + + + +```tsx +import { useAdminCancelFulfillment } from "medusa-react" + +const CancelFulfillment = () => { + const cancelFulfillment = useAdminCancelFulfillment( + orderId + ) + // ... + + const handleCancel = () => { + cancelFulfillment.mutate(fulfillment_id) + } + + // ... +} + +export default CancelFulfillment +``` + + + + + + +```ts +fetch(`/admin/orders/${orderId}/fulfillments/${fulfillmentId}/cancel`, { + credentials: "include", + method: "POST", +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.id) +}) +``` + + + + +```bash +curl -L -X POST '/admin/orders//fulfillments//cancel' \ +-H 'Authorization: Bearer ' +``` + + + + +This endpoint requires passing the order’s ID and fulfillment ID as path parameters. + +The request returns the updated order as an object. + +--- + +## Completing an Order + +You can mark an order completed, changing its status, by sending a request to the [Complete an Order endpoint](/api/admin#tag/Orders/operation/PostOrdersOrderComplete): + + + + +```ts +medusa.admin.orders.complete(orderId) +.then(({ order }) => { + console.log(order.status) +}) +``` + + + + +```tsx +import { useAdminCompleteOrder } from "medusa-react" + +const CompleteOrder = () => { + const completeOrder = useAdminCompleteOrder( + orderId + ) + // ... + + const handleComplete = () => { + completeOrder.mutate() + } + + // ... +} + +export default CompleteOrder +``` + + + + +```ts +fetch(`/admin/orders/${orderId}/complete`, { + credentials: "include", + method: "POST", +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.status) +}) +``` + + + + +```bash +curl -L -X POST '/admin/orders//complete' \ +-H 'Authorization: Bearer ' +``` + + + + +This endpoint requires the order ID to be passed as a path parameter. + +The request returns the updated order as an object. + +--- + +## Cancel an Order + +You can cancel an order by sending a request to the [Cancel Order endpoint](/api/admin#tag/Orders/operation/PostOrdersOrderCancel): + + + + +```ts +medusa.admin.orders.cancel(orderId) +.then(({ order }) => { + console.log(order.status) +}) +``` + + + + +```tsx +import { useAdminCancelOrder } from "medusa-react" + +const CancelOrder = () => { + const cancelOrder = useAdminCancelOrder( + orderId + ) + // ... + + const handleCancel = () => { + cancelOrder.mutate() + } + + // ... +} + +export default CancelOrder +``` + + + + +```ts +fetch(`/admin/orders/${orderId}/cancel`, { + credentials: "include", + method: "POST", +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.status) +}) +``` + + + + +```bash +curl -L -X POST '/admin/orders//cancel' \ +-H 'Authorization: Bearer ' +``` + + + + +This endpoint requires the order ID to be passed as a path parameter. + +The request returns the updated order as an object. + +--- + +## Archive Order + +You can archive an order by sending a request to the [Archive Order endpoint](/api/admin#tag/Orders/operation/PostOrdersOrderArchive): + + + + +```ts +medusa.admin.orders.archive(orderId) +.then(({ order }) => { + console.log(order.status) +}) +``` + + + + +```tsx +import { useAdminArchiveOrder } from "medusa-react" + +const ArchiveOrder = () => { + const archiveOrder = useAdminArchiveOrder( + orderId + ) + // ... + + const handleArchive = () => { + archiveOrder.mutate() + } + + // ... +} + +export default ArchiveOrder +``` + + + + +```ts +fetch(`/admin/orders/${orderId}/archive`, { + credentials: "include", + method: "POST", +}) +.then((response) => response.json()) +.then(({ order }) => { + console.log(order.status) +}) +``` + + + + +```bash +curl -L -X POST '/admin/orders//archive' \ +-H 'Authorization: Bearer ' +``` + + + + +This endpoint requires the order ID to be passed as a path parameter. + +The request returns the updated order as an object. + +--- + +## See Also + +- [How to send an order confirmation email](../backend/send-order-confirmation.md) +- [How to edit an order](./edit-order.mdx) diff --git a/docs/content/modules/orders/overview.mdx b/docs/content/modules/orders/overview.mdx index 4a779efabe..fb5f9f8b6a 100644 --- a/docs/content/modules/orders/overview.mdx +++ b/docs/content/modules/orders/overview.mdx @@ -26,12 +26,11 @@ Customers can view their previous orders.