Feat/show order as allocated (#3497)
**What** - Add check to see if any items is unfulfilled when validating reservations for allocation indicator - Add reservations refresh to onSuccess when creating a fulfillment to automatically update indicators on fulfillment Fixes CORE-1248 Co-authored-by: Sebastian Rindom <7554214+srindom@users.noreply.github.com>
This commit is contained in:
1 parent
e6e5291527
commit
2e12f13565
6 files changed
+54
-41
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/admin-ui": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(admin-ui): fix(admin-ui): ensure that the allocation indicator is correctly displayed
|
||||||
+4
-11
@@ -26,26 +26,19 @@ const EditAllocationDrawer = ({
|
|||||||
close,
|
close,
|
||||||
reservation,
|
reservation,
|
||||||
item,
|
item,
|
||||||
sales_channel_id,
|
|
||||||
totalReservedQuantity,
|
totalReservedQuantity,
|
||||||
}: {
|
}: {
|
||||||
close: () => void
|
close: () => void
|
||||||
reservation?: ReservationItemDTO
|
reservation?: ReservationItemDTO
|
||||||
item: LineItem
|
item: LineItem
|
||||||
totalReservedQuantity: number
|
totalReservedQuantity: number
|
||||||
sales_channel_id?: string
|
|
||||||
}) => {
|
}) => {
|
||||||
const form = useForm<EditAllocationLineItemForm>()
|
const form = useForm<EditAllocationLineItemForm>()
|
||||||
|
|
||||||
const { control, setValue, handleSubmit } = form
|
const { control, setValue, handleSubmit } = form
|
||||||
|
|
||||||
// if not sales channel is present fetch all locations
|
const { stock_locations, isLoading: isLoadingStockLocations } =
|
||||||
const stockLocationsFilter: { sales_channel_id?: string } = {}
|
useAdminStockLocations()
|
||||||
if (sales_channel_id) {
|
|
||||||
stockLocationsFilter.sales_channel_id = sales_channel_id
|
|
||||||
}
|
|
||||||
|
|
||||||
const { stock_locations } = useAdminStockLocations(stockLocationsFilter)
|
|
||||||
|
|
||||||
const { variant, isLoading } = useAdminVariantsInventory(
|
const { variant, isLoading } = useAdminVariantsInventory(
|
||||||
item.variant_id as string
|
item.variant_id as string
|
||||||
@@ -59,14 +52,14 @@ const EditAllocationDrawer = ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const locationOptions = useMemo(() => {
|
const locationOptions = useMemo(() => {
|
||||||
if (!stock_locations) {
|
if (!stock_locations || isLoadingStockLocations) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
return stock_locations.map((sl) => ({
|
return stock_locations.map((sl) => ({
|
||||||
value: sl.id,
|
value: sl.id,
|
||||||
label: sl.name,
|
label: sl.name,
|
||||||
}))
|
}))
|
||||||
}, [stock_locations])
|
}, [isLoadingStockLocations, stock_locations])
|
||||||
|
|
||||||
const notification = useNotification()
|
const notification = useNotification()
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
|
|||||||
@@ -36,12 +36,14 @@ type CreateFulfillmentModalProps = {
|
|||||||
email?: string
|
email?: string
|
||||||
orderToFulfill: Order | ClaimOrder | Swap
|
orderToFulfill: Order | ClaimOrder | Swap
|
||||||
orderId: string
|
orderId: string
|
||||||
|
onComplete?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateFulfillmentModal: React.FC<CreateFulfillmentModalProps> = ({
|
const CreateFulfillmentModal: React.FC<CreateFulfillmentModalProps> = ({
|
||||||
handleCancel,
|
handleCancel,
|
||||||
orderToFulfill,
|
orderToFulfill,
|
||||||
orderId,
|
orderId,
|
||||||
|
onComplete,
|
||||||
}) => {
|
}) => {
|
||||||
const { isFeatureEnabled } = useFeatureFlag()
|
const { isFeatureEnabled } = useFeatureFlag()
|
||||||
const isLocationFulfillmentEnabled =
|
const isLocationFulfillmentEnabled =
|
||||||
@@ -187,6 +189,7 @@ const CreateFulfillmentModal: React.FC<CreateFulfillmentModalProps> = ({
|
|||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
notification("Success", successText, "success")
|
notification("Success", successText, "success")
|
||||||
handleCancel()
|
handleCancel()
|
||||||
|
onComplete && onComplete()
|
||||||
},
|
},
|
||||||
onError: (err) => notification("Error", getErrorMessage(err), "error"),
|
onError: (err) => notification("Error", getErrorMessage(err), "error"),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,19 +11,15 @@ import { OrderEditContext } from "../../edit/context"
|
|||||||
import OrderLine from "../order-line"
|
import OrderLine from "../order-line"
|
||||||
import StatusIndicator from "../../../../components/fundamentals/status-indicator"
|
import StatusIndicator from "../../../../components/fundamentals/status-indicator"
|
||||||
import { sum } from "lodash"
|
import { sum } from "lodash"
|
||||||
import { useAdminReservations } from "medusa-react"
|
|
||||||
import { useFeatureFlag } from "../../../../providers/feature-flag-provider"
|
import { useFeatureFlag } from "../../../../providers/feature-flag-provider"
|
||||||
import useToggleState from "../../../../hooks/use-toggle-state"
|
import useToggleState from "../../../../hooks/use-toggle-state"
|
||||||
|
|
||||||
type SummaryCardProps = {
|
type SummaryCardProps = {
|
||||||
order: Order
|
order: Order
|
||||||
|
reservations: ReservationItemDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const SummaryCard: React.FC<SummaryCardProps> = ({
|
const SummaryCard: React.FC<SummaryCardProps> = ({ order, reservations }) => {
|
||||||
order,
|
|
||||||
}: {
|
|
||||||
order: Order
|
|
||||||
}) => {
|
|
||||||
const {
|
const {
|
||||||
state: allocationModalIsOpen,
|
state: allocationModalIsOpen,
|
||||||
open: showAllocationModal,
|
open: showAllocationModal,
|
||||||
@@ -34,23 +30,8 @@ const SummaryCard: React.FC<SummaryCardProps> = ({
|
|||||||
const { isFeatureEnabled } = useFeatureFlag()
|
const { isFeatureEnabled } = useFeatureFlag()
|
||||||
const inventoryEnabled = isFeatureEnabled("inventoryService")
|
const inventoryEnabled = isFeatureEnabled("inventoryService")
|
||||||
|
|
||||||
const { reservations, isLoading, refetch } = useAdminReservations(
|
|
||||||
{
|
|
||||||
line_item_id: order.items.map((item) => item.id),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: inventoryEnabled,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (inventoryEnabled) {
|
|
||||||
refetch()
|
|
||||||
}
|
|
||||||
}, [inventoryEnabled, refetch])
|
|
||||||
|
|
||||||
const reservationItemsMap = useMemo(() => {
|
const reservationItemsMap = useMemo(() => {
|
||||||
if (!reservations?.length || !inventoryEnabled || isLoading) {
|
if (!reservations?.length || !inventoryEnabled) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,15 +47,17 @@ const SummaryCard: React.FC<SummaryCardProps> = ({
|
|||||||
},
|
},
|
||||||
{}
|
{}
|
||||||
)
|
)
|
||||||
}, [reservations, inventoryEnabled, isLoading])
|
}, [reservations, inventoryEnabled])
|
||||||
|
|
||||||
const allItemsReserved = useMemo(() => {
|
const allItemsReserved = useMemo(() => {
|
||||||
return order.items.every((item) => {
|
return order.items.every((item) => {
|
||||||
const reservations = reservationItemsMap[item.id]
|
const reservations = reservationItemsMap[item.id]
|
||||||
if (!reservations) {
|
|
||||||
return false
|
return (
|
||||||
}
|
item.quantity === item.fulfilled_quantity ||
|
||||||
return sum(reservations.map((r) => r.quantity)) === item.quantity
|
(reservations &&
|
||||||
|
sum(reservations.map((r) => r.quantity)) === item.quantity)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}, [reservationItemsMap, order])
|
}, [reservationItemsMap, order])
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
useAdminCapturePayment,
|
useAdminCapturePayment,
|
||||||
useAdminOrder,
|
useAdminOrder,
|
||||||
useAdminRegion,
|
useAdminRegion,
|
||||||
|
useAdminReservations,
|
||||||
useAdminUpdateOrder,
|
useAdminUpdateOrder,
|
||||||
} from "medusa-react"
|
} from "medusa-react"
|
||||||
import { useNavigate, useParams } from "react-router-dom"
|
import { useNavigate, useParams } from "react-router-dom"
|
||||||
@@ -55,8 +56,9 @@ import useClipboard from "../../../hooks/use-clipboard"
|
|||||||
import { useHotkeys } from "react-hotkeys-hook"
|
import { useHotkeys } from "react-hotkeys-hook"
|
||||||
import useImperativeDialog from "../../../hooks/use-imperative-dialog"
|
import useImperativeDialog from "../../../hooks/use-imperative-dialog"
|
||||||
import useNotification from "../../../hooks/use-notification"
|
import useNotification from "../../../hooks/use-notification"
|
||||||
import { useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import useToggleState from "../../../hooks/use-toggle-state"
|
import useToggleState from "../../../hooks/use-toggle-state"
|
||||||
|
import { useFeatureFlag } from "../../../providers/feature-flag-provider"
|
||||||
|
|
||||||
type OrderDetailFulfillment = {
|
type OrderDetailFulfillment = {
|
||||||
title: string
|
title: string
|
||||||
@@ -145,6 +147,23 @@ const OrderDetails = () => {
|
|||||||
const { region } = useAdminRegion(order?.region_id!, {
|
const { region } = useAdminRegion(order?.region_id!, {
|
||||||
enabled: !!order?.region_id,
|
enabled: !!order?.region_id,
|
||||||
})
|
})
|
||||||
|
const { isFeatureEnabled } = useFeatureFlag()
|
||||||
|
const inventoryEnabled = isFeatureEnabled("inventoryService")
|
||||||
|
|
||||||
|
const { reservations, refetch: refetchReservations } = useAdminReservations(
|
||||||
|
{
|
||||||
|
line_item_id: order?.items.map((item) => item.id),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: inventoryEnabled,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (inventoryEnabled) {
|
||||||
|
refetchReservations()
|
||||||
|
}
|
||||||
|
}, [inventoryEnabled, refetchReservations])
|
||||||
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const notification = useNotification()
|
const notification = useNotification()
|
||||||
@@ -316,7 +335,7 @@ const OrderDetails = () => {
|
|||||||
</div>
|
</div>
|
||||||
</BodyCard>
|
</BodyCard>
|
||||||
|
|
||||||
<SummaryCard order={order} />
|
<SummaryCard order={order} reservations={reservations || []} />
|
||||||
|
|
||||||
<BodyCard
|
<BodyCard
|
||||||
className={"mb-4 h-auto min-h-0 w-full"}
|
className={"mb-4 h-auto min-h-0 w-full"}
|
||||||
@@ -513,6 +532,7 @@ const OrderDetails = () => {
|
|||||||
orderToFulfill={order as any}
|
orderToFulfill={order as any}
|
||||||
handleCancel={() => setShowFulfillment(false)}
|
handleCancel={() => setShowFulfillment(false)}
|
||||||
orderId={order.id}
|
orderId={order.id}
|
||||||
|
onComplete={refetchReservations}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showRefund && (
|
{showRefund && (
|
||||||
|
|||||||
@@ -94,13 +94,17 @@ const ReservationIndicator = ({
|
|||||||
const locationMap = new Map(stock_locations?.map((l) => [l.id, l.name]) || [])
|
const locationMap = new Map(stock_locations?.map((l) => [l.id, l.name]) || [])
|
||||||
|
|
||||||
const reservationsSum = sum(reservations?.map((r) => r.quantity) || [])
|
const reservationsSum = sum(reservations?.map((r) => r.quantity) || [])
|
||||||
const awaitingAllocation = lineItem.quantity - reservationsSum
|
|
||||||
|
const allocatableSum = lineItem.quantity - (lineItem?.fulfilled_quantity || 0)
|
||||||
|
|
||||||
|
const awaitingAllocation = allocatableSum - reservationsSum
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={awaitingAllocation ? "text-rose-50" : "text-grey-40"}>
|
<div className={awaitingAllocation ? "text-rose-50" : "text-grey-40"}>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={
|
content={
|
||||||
<div className="inter-small-regular flex flex-col items-center px-1 pt-1 pb-2">
|
<div className="inter-small-regular flex flex-col items-center px-1 pt-1 pb-2">
|
||||||
|
{reservationsSum || awaitingAllocation ? (
|
||||||
<div className="gap-y-base grid grid-cols-1 divide-y">
|
<div className="gap-y-base grid grid-cols-1 divide-y">
|
||||||
{!!awaitingAllocation && (
|
{!!awaitingAllocation && (
|
||||||
<span className="flex w-full items-center">
|
<span className="flex w-full items-center">
|
||||||
@@ -118,6 +122,11 @@ const ReservationIndicator = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<span className="flex w-full items-center">
|
||||||
|
This item has been fulfilled.
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
side="bottom"
|
side="bottom"
|
||||||
|
|||||||
Reference in new issue
Block a user