feat(dashboard,core-flows,medusa): update fulfillment flows (#7589)
* fix: fulfillment ops * fix: cancel fulfillment route * fix: adjustInventoryLevelsStep throwing * feat: cancel order and fix endpoint * fix: type * feat: order domain sdk * feat: delete unused file * fix: import
This commit is contained in:
+3
-1
@@ -1,5 +1,7 @@
|
||||
import type { FulfillmentStatus } from "@medusajs/medusa"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { FulfillmentStatus } from "@medusajs/types"
|
||||
|
||||
import { getOrderFulfillmentStatus } from "../../../../../lib/order-helpers"
|
||||
import { StatusCell } from "../../common/status-cell"
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { QueryKey, useQuery, UseQueryOptions } from "@tanstack/react-query"
|
||||
|
||||
import { client } from "../../lib/client"
|
||||
import { queryKeysFactory } from "../../lib/query-key-factory"
|
||||
|
||||
const ORDERS_QUERY_KEY = "orders" as const
|
||||
export const ordersQueryKeys = queryKeysFactory(ORDERS_QUERY_KEY)
|
||||
|
||||
export const useOrder = (
|
||||
id: string,
|
||||
query?: Record<string, any>,
|
||||
options?: Omit<
|
||||
UseQueryOptions<any, Error, any, QueryKey>,
|
||||
"queryFn" | "queryKey"
|
||||
>
|
||||
) => {
|
||||
const { data, ...rest } = useQuery({
|
||||
queryFn: async () => client.orders.retrieve(id, query),
|
||||
queryKey: ordersQueryKeys.detail(id, query),
|
||||
...options,
|
||||
})
|
||||
|
||||
return { ...data, ...rest }
|
||||
}
|
||||
|
||||
export const useOrders = (
|
||||
query?: Record<string, any>,
|
||||
options?: Omit<
|
||||
UseQueryOptions<any, Error, any, QueryKey>,
|
||||
"queryFn" | "queryKey"
|
||||
>
|
||||
) => {
|
||||
const { data, ...rest } = useQuery({
|
||||
queryFn: async () => client.orders.list(query),
|
||||
queryKey: ordersQueryKeys.list(query),
|
||||
...options,
|
||||
})
|
||||
|
||||
return { ...data, ...rest }
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import {
|
||||
QueryKey,
|
||||
useMutation,
|
||||
UseMutationOptions,
|
||||
useQuery,
|
||||
UseQueryOptions,
|
||||
} from "@tanstack/react-query"
|
||||
|
||||
import { queryClient } from "../../lib/query-client"
|
||||
import { queryKeysFactory } from "../../lib/query-key-factory"
|
||||
import { sdk } from "../../lib/client"
|
||||
|
||||
const ORDERS_QUERY_KEY = "orders" as const
|
||||
export const ordersQueryKeys = queryKeysFactory(ORDERS_QUERY_KEY)
|
||||
|
||||
export const useOrder = (
|
||||
id: string,
|
||||
query?: Record<string, any>,
|
||||
options?: Omit<
|
||||
UseQueryOptions<any, Error, any, QueryKey>,
|
||||
"queryFn" | "queryKey"
|
||||
>
|
||||
) => {
|
||||
const { data, ...rest } = useQuery({
|
||||
queryFn: async () => sdk.admin.order.retrieve(id, query),
|
||||
queryKey: ordersQueryKeys.detail(id, query),
|
||||
...options,
|
||||
})
|
||||
|
||||
return { ...data, ...rest }
|
||||
}
|
||||
|
||||
export const useOrders = (
|
||||
query?: Record<string, any>,
|
||||
options?: Omit<
|
||||
UseQueryOptions<any, Error, any, QueryKey>,
|
||||
"queryFn" | "queryKey"
|
||||
>
|
||||
) => {
|
||||
const { data, ...rest } = useQuery({
|
||||
queryFn: async () => sdk.admin.order.list(query),
|
||||
queryKey: ordersQueryKeys.list(query),
|
||||
...options,
|
||||
})
|
||||
|
||||
return { ...data, ...rest }
|
||||
}
|
||||
|
||||
export const useCreateOrderFulfillment = (
|
||||
orderId: string,
|
||||
options?: UseMutationOptions<any, Error, any>
|
||||
) => {
|
||||
return useMutation({
|
||||
mutationFn: (payload: any) =>
|
||||
sdk.admin.order.createFulfillment(orderId, payload),
|
||||
onSuccess: (data: any, variables: any, context: any) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ordersQueryKeys.details(),
|
||||
})
|
||||
options?.onSuccess?.(data, variables, context)
|
||||
},
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
export const useCancelOrderFulfillment = (
|
||||
orderId: string,
|
||||
fulfillmentId: string,
|
||||
options?: UseMutationOptions<any, Error, any>
|
||||
) => {
|
||||
return useMutation({
|
||||
mutationFn: (payload: { no_notification?: boolean }) =>
|
||||
sdk.admin.order.cancelFulfillment(orderId, fulfillmentId, payload),
|
||||
onSuccess: (data: any, variables: any, context: any) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ordersQueryKeys.details(),
|
||||
})
|
||||
options?.onSuccess?.(data, variables, context)
|
||||
},
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
export const useCancelOrder = (
|
||||
orderId: string,
|
||||
options?: UseMutationOptions<any, Error, any>
|
||||
) => {
|
||||
return useMutation({
|
||||
mutationFn: () => sdk.admin.order.cancel(orderId),
|
||||
onSuccess: (data: any, variables: any, context: any) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ordersQueryKeys.details(),
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ordersQueryKeys.lists(),
|
||||
})
|
||||
options?.onSuccess?.(data, variables, context)
|
||||
},
|
||||
...options,
|
||||
})
|
||||
}
|
||||
@@ -76,6 +76,7 @@
|
||||
"back": "Back",
|
||||
"close": "Close",
|
||||
"continue": "Continue",
|
||||
"reset": "Reset",
|
||||
"confirm": "Confirm",
|
||||
"edit": "Edit",
|
||||
"download": "Download",
|
||||
@@ -572,6 +573,7 @@
|
||||
"inStock": "In stock",
|
||||
"itemsToFulfillDesc": "Choose items and quantities to fulfill",
|
||||
"locationDescription": "Choose which location you want to fulfill items from.",
|
||||
"sendNotificationHint": "Notify customers about the created fulfillment.",
|
||||
"error": {
|
||||
"wrongQuantity": "Only one item is available for fulfillment",
|
||||
"wrongQuantity_other": "Quantity should be a number between 1 and {{number}}",
|
||||
|
||||
@@ -8,7 +8,6 @@ import { fulfillmentProviders } from "./fulfillment-providers"
|
||||
import { fulfillments } from "./fulfillments"
|
||||
import { inventoryItems } from "./inventory"
|
||||
import { invites } from "./invites"
|
||||
import { orders } from "./orders"
|
||||
import { payments } from "./payments"
|
||||
import { priceLists } from "./price-lists"
|
||||
import { productTypes } from "./product-types"
|
||||
|
||||
@@ -3,10 +3,18 @@ import { CreateFulfillmentDTO } from "@medusajs/types"
|
||||
import { FulfillmentRes } from "../../types/api-responses"
|
||||
import { postRequest } from "./common"
|
||||
|
||||
/**
|
||||
* Create a fulfillment.
|
||||
* NOTE: to create a fulfillment on an order use orders/:id/fulfillments endpoint
|
||||
*/
|
||||
async function createFulfillment(payload: CreateFulfillmentDTO) {
|
||||
return postRequest<FulfillmentRes>(`/admin/fulfillments`, payload)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a fulfillment.
|
||||
* NOTE: to cancel a fulfillment on an order use orders/:id/fulfillments/:id/cancel endpoint
|
||||
*/
|
||||
async function cancelFulfillment(id: string) {
|
||||
return postRequest<FulfillmentRes>(`/admin/fulfillments/${id}/cancel`)
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { getRequest } from "./common"
|
||||
import { OrderListRes, OrderRes } from "../../types/api-responses"
|
||||
|
||||
async function retrieveOrder(id: string, query?: Record<string, any>) {
|
||||
return getRequest<OrderRes, Record<string, any>>(`/admin/orders/${id}`, query)
|
||||
}
|
||||
|
||||
async function listOrders(query?: Record<string, any>) {
|
||||
return getRequest<OrderListRes, Record<string, any>>(`/admin/orders`, query)
|
||||
}
|
||||
|
||||
export const orders = {
|
||||
list: listOrders,
|
||||
retrieve: retrieveOrder,
|
||||
}
|
||||
+10
-10
@@ -14,22 +14,22 @@ import { useTranslation } from "react-i18next"
|
||||
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
|
||||
import { DataGrid } from "../../../../../components/grid/data-grid/index.ts"
|
||||
import { CurrencyCell } from "../../../../../components/grid/grid-cells/common/currency-cell/index.ts"
|
||||
import { DataGridMeta } from "../../../../../components/grid/types.ts"
|
||||
import { DataGrid } from "../../../../../components/grid/data-grid/index"
|
||||
import { CurrencyCell } from "../../../../../components/grid/grid-cells/common/currency-cell/index"
|
||||
import { DataGridMeta } from "../../../../../components/grid/types"
|
||||
import {
|
||||
RouteFocusModal,
|
||||
useRouteModal,
|
||||
} from "../../../../../components/route-modal/index.ts"
|
||||
import { useCurrencies } from "../../../../../hooks/api/currencies.tsx"
|
||||
import { useRegions } from "../../../../../hooks/api/regions.tsx"
|
||||
import { useUpdateShippingOptions } from "../../../../../hooks/api/shipping-options.ts"
|
||||
import { useStore } from "../../../../../hooks/api/store.tsx"
|
||||
} from "../../../../../components/route-modal/index"
|
||||
import { useCurrencies } from "../../../../../hooks/api/currencies"
|
||||
import { useRegions } from "../../../../../hooks/api/regions"
|
||||
import { useUpdateShippingOptions } from "../../../../../hooks/api/shipping-options"
|
||||
import { useStore } from "../../../../../hooks/api/store"
|
||||
import {
|
||||
getDbAmount,
|
||||
getPresentationalAmount,
|
||||
} from "../../../../../lib/money-amount-helpers.ts"
|
||||
import { ExtendedProductDTO } from "../../../../../types/api-responses.ts"
|
||||
} from "../../../../../lib/money-amount-helpers"
|
||||
import { ExtendedProductDTO } from "../../../../../types/api-responses"
|
||||
|
||||
const getInitialCurrencyPrices = (prices: PriceDTO[]) => {
|
||||
const ret: Record<string, number> = {}
|
||||
|
||||
+45
-85
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next"
|
||||
import * as zod from "zod"
|
||||
|
||||
import { AdminOrder } from "@medusajs/types"
|
||||
import { Alert, Button, Select, toast } from "@medusajs/ui"
|
||||
import { Alert, Button, Select, Switch, toast } from "@medusajs/ui"
|
||||
import { useForm, useWatch } from "react-hook-form"
|
||||
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
@@ -12,13 +12,12 @@ import {
|
||||
RouteFocusModal,
|
||||
useRouteModal,
|
||||
} from "../../../../../components/route-modal"
|
||||
import { useCreateFulfillment } from "../../../../../hooks/api/fulfillment"
|
||||
import { useFulfillmentProviders } from "../../../../../hooks/api/fulfillment-providers"
|
||||
import { useStockLocations } from "../../../../../hooks/api/stock-locations"
|
||||
import { cleanNonValues, pick } from "../../../../../lib/common"
|
||||
import { getFulfillableQuantity } from "../../../../../lib/order-item"
|
||||
import { CreateFulfillmentSchema } from "./constants"
|
||||
import { OrderCreateFulfillmentItem } from "./order-create-fulfillment-item"
|
||||
import { useCreateOrderFulfillment } from "../../../../../hooks/api/orders"
|
||||
import { CreateFulfillmentSchema } from "./constants"
|
||||
|
||||
type OrderCreateFulfillmentFormProps = {
|
||||
order: AdminOrder
|
||||
@@ -30,8 +29,8 @@ export function OrderCreateFulfillmentForm({
|
||||
const { t } = useTranslation()
|
||||
const { handleSuccess } = useRouteModal()
|
||||
|
||||
const { mutateAsync: createOrderFulfillment, isLoading: isMutating } =
|
||||
useCreateFulfillment()
|
||||
const { mutateAsync: createOrderFulfillment, isPending: isMutating } =
|
||||
useCreateOrderFulfillment(order.id)
|
||||
|
||||
const { fulfillment_providers } = useFulfillmentProviders({
|
||||
region_id: order.region_id,
|
||||
@@ -43,14 +42,11 @@ export function OrderCreateFulfillmentForm({
|
||||
|
||||
const form = useForm<zod.infer<typeof CreateFulfillmentSchema>>({
|
||||
defaultValues: {
|
||||
quantity: fulfillableItems.reduce(
|
||||
(acc, item) => {
|
||||
acc[item.id] = getFulfillableQuantity(item)
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, number>
|
||||
),
|
||||
// send_notification: !order.no_notification,
|
||||
quantity: fulfillableItems.reduce((acc, item) => {
|
||||
acc[item.id] = getFulfillableQuantity(item)
|
||||
return acc
|
||||
}, {} as Record<string, number>),
|
||||
send_notification: !order.no_notification,
|
||||
},
|
||||
resolver: zodResolver(CreateFulfillmentSchema),
|
||||
})
|
||||
@@ -61,49 +57,13 @@ export function OrderCreateFulfillmentForm({
|
||||
try {
|
||||
await createOrderFulfillment({
|
||||
location_id: data.location_id,
|
||||
/**
|
||||
* TODO: send notification flag
|
||||
*/
|
||||
// no_notification: !data.send_notification,
|
||||
delivery_address: cleanNonValues(
|
||||
pick(order.shipping_address, [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"phone",
|
||||
"company",
|
||||
"address_1",
|
||||
"address_2",
|
||||
"city",
|
||||
"country_code",
|
||||
"province",
|
||||
"postal_code",
|
||||
"metadata",
|
||||
])
|
||||
), // TODO: this should be pulled from order in the workflow
|
||||
provider_id: fulfillment_providers[0]?.id,
|
||||
no_notification: !data.send_notification,
|
||||
items: Object.entries(data.quantity)
|
||||
.filter(([, value]) => !!value)
|
||||
.map(([item_id, quantity]) => {
|
||||
const item = order.items.find((i) => i.id === item_id)
|
||||
|
||||
return {
|
||||
quantity,
|
||||
line_item_id: item_id,
|
||||
title: item.title,
|
||||
barcode: item.variant.barcode || "",
|
||||
sku: item.variant_sku || "",
|
||||
}
|
||||
}),
|
||||
// TODO: should be optional in the enpoint?
|
||||
labels: [
|
||||
{
|
||||
tracking_number: "TODO",
|
||||
tracking_url: "TODO",
|
||||
label_url: "TODO",
|
||||
},
|
||||
],
|
||||
order: {}, // TODO ?
|
||||
order_id: order.id, // TEMP link for now
|
||||
.map(([id, quantity]) => ({
|
||||
id,
|
||||
quantity,
|
||||
})),
|
||||
})
|
||||
|
||||
handleSuccess(`/orders/${order.id}`)
|
||||
@@ -252,36 +212,36 @@ export function OrderCreateFulfillmentForm({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/*<div className="mt-8 pt-8 ">*/}
|
||||
{/* <Form.Field*/}
|
||||
{/* control={form.control}*/}
|
||||
{/* name="send_notification"*/}
|
||||
{/* render={({ field: { onChange, value, ...field } }) => {*/}
|
||||
{/* return (*/}
|
||||
{/* <Form.Item>*/}
|
||||
{/* <div className="flex items-center justify-between">*/}
|
||||
{/* <Form.Label>*/}
|
||||
{/* {t("orders.returns.sendNotification")}*/}
|
||||
{/* </Form.Label>*/}
|
||||
{/* <Form.Control>*/}
|
||||
{/* <Form.Control>*/}
|
||||
{/* <Switch*/}
|
||||
{/* checked={!!value}*/}
|
||||
{/* onCheckedChange={onChange}*/}
|
||||
{/* {...field}*/}
|
||||
{/* />*/}
|
||||
{/* </Form.Control>*/}
|
||||
{/* </Form.Control>*/}
|
||||
{/* </div>*/}
|
||||
{/* <Form.Hint className="!mt-1">*/}
|
||||
{/* {t("orders.returns.sendNotificationHint")}*/}
|
||||
{/* </Form.Hint>*/}
|
||||
{/* <Form.ErrorMessage />*/}
|
||||
{/* </Form.Item>*/}
|
||||
{/* )*/}
|
||||
{/* }}*/}
|
||||
{/* />*/}
|
||||
{/*</div>*/}
|
||||
<div className="mt-8 pt-8 ">
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="send_notification"
|
||||
render={({ field: { onChange, value, ...field } }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<div className="flex items-center justify-between">
|
||||
<Form.Label>
|
||||
{t("orders.returns.sendNotification")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Form.Control>
|
||||
<Switch
|
||||
checked={!!value}
|
||||
onCheckedChange={onChange}
|
||||
{...field}
|
||||
/>
|
||||
</Form.Control>
|
||||
</Form.Control>
|
||||
</div>
|
||||
<Form.Hint className="!mt-1">
|
||||
{t("orders.fulfillment.sendNotificationHint")}
|
||||
</Form.Hint>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -21,10 +21,10 @@ import { Link } from "react-router-dom"
|
||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||
import { Skeleton } from "../../../../../components/common/skeleton"
|
||||
import { Thumbnail } from "../../../../../components/common/thumbnail"
|
||||
import { useCancelFulfillment } from "../../../../../hooks/api/fulfillment"
|
||||
import { useStockLocation } from "../../../../../hooks/api/stock-locations"
|
||||
import { formatProvider } from "../../../../../lib/format-provider"
|
||||
import { getLocaleAmount } from "../../../../../lib/money-amount-helpers"
|
||||
import { useCancelOrderFulfillment } from "../../../../../hooks/api/orders"
|
||||
|
||||
type OrderFulfillmentSectionProps = {
|
||||
order: AdminOrder
|
||||
@@ -186,7 +186,7 @@ const Fulfillment = ({
|
||||
statusTimestamp = fulfillment.shipped_at
|
||||
}
|
||||
|
||||
const { mutateAsync } = useCancelFulfillment(fulfillment.id)
|
||||
const { mutateAsync } = useCancelOrderFulfillment(order.id, fulfillment.id)
|
||||
|
||||
const handleCancel = async () => {
|
||||
if (fulfillment.shipped_at) {
|
||||
@@ -206,7 +206,7 @@ const Fulfillment = ({
|
||||
|
||||
if (res) {
|
||||
try {
|
||||
await mutateAsync(fulfillment.id)
|
||||
await mutateAsync()
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("orders.fulfillment.toast.canceled"),
|
||||
|
||||
+9
-12
@@ -15,6 +15,7 @@ import {
|
||||
getOrderFulfillmentStatus,
|
||||
getOrderPaymentStatus,
|
||||
} from "../../../../../lib/order-helpers"
|
||||
import { useCancelOrder } from "../../../../../hooks/api/orders"
|
||||
|
||||
type OrderGeneralSectionProps = {
|
||||
order: Order
|
||||
@@ -24,7 +25,7 @@ export const OrderGeneralSection = ({ order }: OrderGeneralSectionProps) => {
|
||||
const { t } = useTranslation()
|
||||
const prompt = usePrompt()
|
||||
|
||||
const { mutateAsync } = { mutateAsync: () => {} } // cancel order
|
||||
const { mutateAsync } = useCancelOrder(order.id)
|
||||
|
||||
const handleCancel = async () => {
|
||||
const res = await prompt({
|
||||
@@ -40,7 +41,7 @@ export const OrderGeneralSection = ({ order }: OrderGeneralSectionProps) => {
|
||||
return
|
||||
}
|
||||
|
||||
await mutateAsync(undefined)
|
||||
await mutateAsync()
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -60,17 +61,18 @@ export const OrderGeneralSection = ({ order }: OrderGeneralSectionProps) => {
|
||||
<div className="flex items-center gap-x-4">
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<PaymentBadge order={order} />
|
||||
{/*TODO: SHOW ORDER STATUS INSTEAD OF FULFILLMENT STATUS HERE - if the last fulfillment is canceled it looks like the order is canceled*/}
|
||||
<FulfillmentBadge order={order} />
|
||||
</div>
|
||||
<ActionMenu
|
||||
groups={[
|
||||
{
|
||||
actions: [
|
||||
// {
|
||||
// label: t("actions.cancel"),
|
||||
// onClick: handleCancel,
|
||||
// icon: <XCircle />,
|
||||
// },
|
||||
{
|
||||
label: t("actions.cancel"),
|
||||
onClick: handleCancel,
|
||||
icon: <XCircle />,
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
@@ -83,11 +85,6 @@ export const OrderGeneralSection = ({ order }: OrderGeneralSectionProps) => {
|
||||
const FulfillmentBadge = ({ order }: { order: Order }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
/**
|
||||
* TODO: revisit when Order<>Fulfillment are linked
|
||||
*/
|
||||
return null
|
||||
|
||||
const { label, color } = getOrderFulfillmentStatus(
|
||||
t,
|
||||
order.fulfillment_status
|
||||
|
||||
@@ -3,7 +3,6 @@ const DEFAULT_PROPERTIES = [
|
||||
"status",
|
||||
"created_at",
|
||||
"email",
|
||||
// "fulfillment_status", // -> TODO replacement for this
|
||||
// "payment_status", // -> TODO replacement for this
|
||||
"display_id",
|
||||
"currency_code",
|
||||
|
||||
@@ -4,7 +4,6 @@ const DEFAULT_PROPERTIES = [
|
||||
"created_at",
|
||||
"email",
|
||||
"display_id",
|
||||
// "fulfillment_status", // -> TODO replacement for this
|
||||
// "payment_status", // -> TODO replacement for this
|
||||
"total",
|
||||
"currency_code",
|
||||
|
||||
@@ -4,7 +4,7 @@ import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
type CancelOrderFulfillmentStepInput = CancelOrderFulfillmentDTO
|
||||
|
||||
export const cancelOrderFulfillmentStepId = "cancel-order-fullfillment"
|
||||
export const cancelOrderFulfillmentStepId = "cancel-order-fulfillment"
|
||||
export const cancelOrderFulfillmentStep = createStep(
|
||||
cancelOrderFulfillmentStepId,
|
||||
async (data: CancelOrderFulfillmentStepInput, { container }) => {
|
||||
|
||||
@@ -87,11 +87,14 @@ function prepareInventoryUpdate({
|
||||
}[] = []
|
||||
|
||||
for (const item of fulfillment.items) {
|
||||
inventoryAdjustment.push({
|
||||
inventory_item_id: item.inventory_item_id as string,
|
||||
location_id: fulfillment.location_id,
|
||||
adjustment: item.quantity,
|
||||
})
|
||||
// if this is `null` this means that item is from variant that has `manage_inventory` false
|
||||
if (item.inventory_item_id) {
|
||||
inventoryAdjustment.push({
|
||||
inventory_item_id: item.inventory_item_id as string,
|
||||
location_id: fulfillment.location_id,
|
||||
adjustment: item.quantity,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Product } from "./product"
|
||||
import { ProductCollection } from "./product-collection"
|
||||
import { Region } from "./region"
|
||||
import { Upload } from "./upload"
|
||||
import { Order } from "./order"
|
||||
|
||||
export class Admin {
|
||||
public invite: Invite
|
||||
@@ -13,6 +14,7 @@ export class Admin {
|
||||
public product: Product
|
||||
public upload: Upload
|
||||
public region: Region
|
||||
public order: Order
|
||||
|
||||
constructor(client: Client) {
|
||||
this.invite = new Invite(client)
|
||||
@@ -21,5 +23,6 @@ export class Admin {
|
||||
this.product = new Product(client)
|
||||
this.upload = new Upload(client)
|
||||
this.region = new Region(client)
|
||||
this.order = new Order(client)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
AdminCancelOrderFulfillment,
|
||||
FindParams,
|
||||
HttpTypes,
|
||||
PaginatedResponse,
|
||||
SelectParams,
|
||||
} from "@medusajs/types"
|
||||
import { Client } from "../client"
|
||||
import { ClientHeaders } from "../types"
|
||||
|
||||
export class Order {
|
||||
private client: Client
|
||||
constructor(client: Client) {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
async retrieve(id: string, query?: SelectParams, headers?: ClientHeaders) {
|
||||
return await this.client.fetch<{ order: HttpTypes.AdminOrder }>(
|
||||
`/admin/orders/${id}`,
|
||||
{
|
||||
query,
|
||||
headers,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async list(
|
||||
queryParams?: FindParams & HttpTypes.AdminOrderFilters,
|
||||
headers?: ClientHeaders
|
||||
) {
|
||||
return await this.client.fetch<
|
||||
PaginatedResponse<{ orders: HttpTypes.AdminOrder[] }>
|
||||
>(`/admin/orders`, {
|
||||
query: queryParams,
|
||||
headers,
|
||||
})
|
||||
}
|
||||
|
||||
async cancel(id: string, headers?: ClientHeaders) {
|
||||
return await this.client.fetch<{ order: HttpTypes.AdminOrder }>(
|
||||
`/admin/orders/${id}/cancel`,
|
||||
{
|
||||
method: "POST",
|
||||
headers,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async createFulfillment(
|
||||
id: string,
|
||||
body: HttpTypes.AdminCreateOrderFulfillment,
|
||||
query?: SelectParams,
|
||||
headers?: ClientHeaders
|
||||
) {
|
||||
return await this.client.fetch<{ order: HttpTypes.AdminOrder }>(
|
||||
`/admin/orders/${id}/fulfillments`,
|
||||
{
|
||||
method: "POST",
|
||||
headers,
|
||||
body,
|
||||
query,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async cancelFulfillment(
|
||||
id: string,
|
||||
fulfillmentId: string,
|
||||
body: HttpTypes.AdminCancelOrderFulfillment,
|
||||
headers?: ClientHeaders
|
||||
) {
|
||||
return await this.client.fetch<{ order: HttpTypes.AdminOrder }>(
|
||||
`/admin/orders/${id}/fulfillments/${fulfillmentId}/cancel`,
|
||||
{
|
||||
method: "POST",
|
||||
headers,
|
||||
body,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,24 @@
|
||||
import {
|
||||
BaseOrder,
|
||||
BaseOrderAddress,
|
||||
BaseOrderFilters,
|
||||
BaseOrderLineItem,
|
||||
BaseOrderShippingMethod,
|
||||
} from "./common"
|
||||
|
||||
export interface AdminOrder extends BaseOrder {}
|
||||
export interface AdminOrderLineItem extends BaseOrderLineItem {}
|
||||
export interface AdminOrderFilters extends BaseOrderFilters {}
|
||||
export interface AdminOrderAddress extends BaseOrderAddress {}
|
||||
export interface AdminOrderShippingMethod extends BaseOrderShippingMethod {}
|
||||
|
||||
export interface AdminCreateOrderFulfillment {
|
||||
items: { id: string; quantity: number }[]
|
||||
location_id?: string
|
||||
no_notification?: boolean
|
||||
metadata?: Record<string, any>
|
||||
}
|
||||
|
||||
export interface AdminCancelOrderFulfillment {
|
||||
no_notification?: boolean
|
||||
}
|
||||
|
||||
@@ -1109,7 +1109,7 @@ export interface OrderDTO {
|
||||
raw_original_shipping_tax_total: BigNumberRawValue
|
||||
}
|
||||
|
||||
type PaymentStatus =
|
||||
export type PaymentStatus =
|
||||
| "not_paid"
|
||||
| "awaiting"
|
||||
| "authorized"
|
||||
@@ -1121,7 +1121,7 @@ type PaymentStatus =
|
||||
| "canceled"
|
||||
| "requires_action"
|
||||
|
||||
type FulfillmentStatus =
|
||||
export type FulfillmentStatus =
|
||||
| "not_fulfilled"
|
||||
| "partially_fulfilled"
|
||||
| "fulfilled"
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
MedusaResponse,
|
||||
} from "../../../../../types/routing"
|
||||
|
||||
export const GET = async (
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
|
||||
+1
@@ -20,6 +20,7 @@ export const POST = async (
|
||||
const input = {
|
||||
...req.validatedBody,
|
||||
order_id: req.params.id,
|
||||
fulfillment_id: req.params.fulfillment_id,
|
||||
}
|
||||
|
||||
await cancelOrderFulfillmentWorkflow(req.scope).run({
|
||||
|
||||
@@ -12,8 +12,8 @@ export const GET = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const worklow = getOrderDetailWorkflow(req.scope)
|
||||
const { result } = await worklow.run({
|
||||
const workflow = getOrderDetailWorkflow(req.scope)
|
||||
const { result } = await workflow.run({
|
||||
input: {
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
order_id: req.params.id,
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
AdminCompleteOrder,
|
||||
AdminGetOrdersOrderParams,
|
||||
AdminGetOrdersParams,
|
||||
AdminOrderCancelFulfillment,
|
||||
AdminOrderCreateFulfillment,
|
||||
} from "./validators"
|
||||
|
||||
@@ -78,9 +79,9 @@ export const adminOrderRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/orders/:id/fulfillments/cancel",
|
||||
matcher: "/admin/orders/:id/fulfillments/:fulfillment_id/cancel",
|
||||
middlewares: [
|
||||
// validateAndTransformBody(),
|
||||
validateAndTransformBody(AdminOrderCancelFulfillment),
|
||||
validateAndTransformQuery(
|
||||
AdminGetOrdersOrderParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
|
||||
@@ -81,7 +81,6 @@ export type AdminOrderCreateShipmentType = z.infer<
|
||||
>
|
||||
|
||||
export const AdminOrderCancelFulfillment = z.object({
|
||||
fulfillment_id: z.string(),
|
||||
no_notification: z.boolean().optional(),
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user