feat(core-flows,medusa,utils,types): adds delivered_quantity to order (#9130)

what:

- adds delivered_quantity to order


https://github.com/user-attachments/assets/709b1727-08ed-4a88-ae29-38f13540e301
This commit is contained in:
Riqwan Thamir
2024-09-16 11:59:01 +02:00
committed by GitHub
parent 950cf9af79
commit 3e97a64b21
41 changed files with 794 additions and 25 deletions

View File

@@ -1,3 +1,5 @@
import { FetchError } from "@medusajs/js-sdk"
import { HttpTypes } from "@medusajs/types"
import {
QueryKey,
useMutation,
@@ -5,8 +7,6 @@ import {
useQuery,
UseQueryOptions,
} from "@tanstack/react-query"
import { FetchError } from "@medusajs/js-sdk"
import { HttpTypes } from "@medusajs/types"
import { sdk } from "../../lib/client"
import { queryClient } from "../../lib/query-client"
import { queryKeysFactory, TQueryKey } from "../../lib/query-key-factory"
@@ -184,6 +184,33 @@ export const useCreateOrderShipment = (
})
}
export const useMarkOrderFulfillmentAsDelivered = (
orderId: string,
fulfillmentId: string,
options?: UseMutationOptions<
{ order: HttpTypes.AdminOrder },
FetchError,
HttpTypes.AdminMarkOrderFulfillmentAsDelivered
>
) => {
return useMutation({
mutationFn: (payload: HttpTypes.AdminMarkOrderFulfillmentAsDelivered) =>
sdk.admin.order.markAsDelivered(orderId, fulfillmentId, payload),
onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.all,
})
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.preview(orderId),
})
options?.onSuccess?.(data, variables, context)
},
...options,
})
}
export const useCancelOrder = (
orderId: string,
options?: UseMutationOptions<any, FetchError, any>

View File

@@ -1065,6 +1065,7 @@
},
"fulfillment": {
"cancelWarning": "You are about to cancel a fulfillment. This action cannot be undone.",
"markAsDeliveredWarning": "You are about to mark fulfillment as delivered. This action cannot be undone.",
"unfulfilledItems": "Unfulfilled Items",
"statusLabel": "Fulfillment status",
"statusTitle": "Fulfillment Status",
@@ -1076,6 +1077,7 @@
"available": "Available",
"inStock": "In stock",
"markAsShipped": "Mark as shipped",
"markAsDelivered": "Mark as delivered",
"itemsToFulfillDesc": "Choose items and quantities to fulfill",
"locationDescription": "Choose which location you want to fulfill items from.",
"sendNotificationHint": "Notify customers about the created fulfillment.",
@@ -1091,6 +1093,8 @@
"fulfilled": "Fulfilled",
"partiallyShipped": "Partially shipped",
"shipped": "Shipped",
"delivered": "Delivered",
"partiallyDelivered": "Partially delivered",
"partiallyReturned": "Partially returned",
"returned": "Returned",
"canceled": "Canceled",
@@ -1099,7 +1103,8 @@
"toast": {
"created": "Fulfillment created successfully",
"canceled": "Fulfillment successfully canceled",
"fulfillmentShipped": "Cannot cancel an already shipped fulfillment"
"fulfillmentShipped": "Cannot cancel an already shipped fulfillment",
"fulfillmentDelivered": "Fulfillment marked as delivered successfully"
},
"trackingLabel": "Tracking",
"shippingFromLabel": "Shipping from",
@@ -1155,6 +1160,7 @@
"created": "Items fulfilled",
"canceled": "Fulfillment canceled",
"shipped": "Items shipped",
"delivered": "Items delivered",
"items_one": "{{count}} item",
"items_other": "{{count}} items"
},

View File

@@ -45,6 +45,11 @@ export const getOrderFulfillmentStatus = (
"orange",
],
shipped: [t("orders.fulfillment.status.shipped"), "green"],
delivered: [t("orders.fulfillment.status.delivered"), "green"],
partially_delivered: [
t("orders.fulfillment.status.partiallyDelivered"),
"orange",
],
partially_returned: [
t("orders.fulfillment.status.partiallyReturned"),
"orange",

View File

@@ -16,6 +16,7 @@ import {
import { useTranslation } from "react-i18next"
import { AdminOrderLineItem } from "@medusajs/types"
import { useOrderChanges } from "../../../../../hooks/api"
import { useCancelClaim, useClaims } from "../../../../../hooks/api/claims"
import {
useCancelExchange,
@@ -25,7 +26,6 @@ import { useCancelReturn, useReturns } from "../../../../../hooks/api/returns"
import { useDate } from "../../../../../hooks/use-date"
import { getStylizedAmount } from "../../../../../lib/money-amount-helpers"
import { getPaymentsFromOrder } from "../order-payment-section"
import { useOrderChanges } from "../../../../../hooks/api"
import ActivityItems from "./activity-items"
type OrderTimelineProps = {
@@ -222,6 +222,16 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
children: <FulfillmentCreatedBody fulfillment={fulfillment} />,
})
if (fulfillment.delivered_at) {
items.push({
title: t("orders.activity.events.fulfillment.delivered"),
timestamp: fulfillment.delivered_at,
children: (
<FulfillmentCreatedBody fulfillment={fulfillment} />
),
})
}
if (fulfillment.shipped_at) {
items.push({
title: t("orders.activity.events.fulfillment.shipped"),
@@ -340,10 +350,10 @@ const useActivityItems = (order: AdminOrder): Activity[] => {
edit.status === "requested"
? edit.requested_at
: edit.status === "declined"
? edit.declined_at
: edit.status === "canceled"
? edit.canceled_at
: edit.created_at,
? edit.declined_at
: edit.status === "canceled"
? edit.canceled_at
: edit.created_at,
children: isConfirmed ? (
<OrderEditBody edit={edit} itemsMap={itemsMap} />
) : null,

View File

@@ -22,7 +22,10 @@ import { Link, useNavigate } from "react-router-dom"
import { ActionMenu } from "../../../../../components/common/action-menu"
import { Skeleton } from "../../../../../components/common/skeleton"
import { Thumbnail } from "../../../../../components/common/thumbnail"
import { useCancelOrderFulfillment } from "../../../../../hooks/api/orders"
import {
useCancelOrderFulfillment,
useMarkOrderFulfillmentAsDelivered,
} from "../../../../../hooks/api/orders"
import { useStockLocation } from "../../../../../hooks/api/stock-locations"
import { formatProvider } from "../../../../../lib/format-provider"
import { getLocaleAmount } from "../../../../../lib/money-amount-helpers"
@@ -183,6 +186,10 @@ const Fulfillment = ({
statusText = "Canceled"
statusColor = "red"
statusTimestamp = fulfillment.canceled_at
} else if (fulfillment.delivered_at) {
statusText = "Delivered"
statusColor = "green"
statusTimestamp = fulfillment.delivered_at
} else if (fulfillment.shipped_at) {
statusText = "Shipped"
statusColor = "green"
@@ -190,8 +197,41 @@ const Fulfillment = ({
}
const { mutateAsync } = useCancelOrderFulfillment(order.id, fulfillment.id)
const { mutateAsync: markAsDelivered } = useMarkOrderFulfillmentAsDelivered(
order.id,
fulfillment.id
)
const showShippingButton = !fulfillment.canceled_at && !fulfillment.shipped_at
const showShippingButton =
!fulfillment.canceled_at &&
!fulfillment.shipped_at &&
!fulfillment.delivered_at
const showDeliveryButton =
!fulfillment.canceled_at && !fulfillment.delivered_at
const handleMarkAsDelivered = async () => {
const res = await prompt({
title: t("general.areYouSure"),
description: t("orders.fulfillment.markAsDeliveredWarning"),
confirmText: t("actions.continue"),
cancelText: t("actions.cancel"),
variant: "confirmation",
})
if (res) {
await markAsDelivered(
{},
{
onSuccess: () => {
toast.success(t("orders.fulfillment.toast.fulfillmentDelivered"))
},
onError: (e) => {
toast.error(e.message)
},
}
)
}
}
const handleCancel = async () => {
if (fulfillment.shipped_at) {
@@ -343,14 +383,23 @@ const Fulfillment = ({
)}
</div>
</div>
{showShippingButton && (
<div className="bg-ui-bg-subtle flex items-center justify-end rounded-b-xl px-4 py-4">
<Button
onClick={() => navigate(`./${fulfillment.id}/create-shipment`)}
variant="secondary"
>
{t("orders.fulfillment.markAsShipped")}
</Button>
{(showShippingButton || showDeliveryButton) && (
<div className="bg-ui-bg-subtle flex items-center justify-end rounded-b-xl px-4 py-4 gap-x-2">
{showDeliveryButton && (
<Button onClick={handleMarkAsDelivered} variant="secondary">
{t("orders.fulfillment.markAsDelivered")}
</Button>
)}
{showShippingButton && (
<Button
onClick={() => navigate(`./${fulfillment.id}/create-shipment`)}
variant="secondary"
>
{t("orders.fulfillment.markAsShipped")}
</Button>
)}
</div>
)}
</Container>