From feaf8d2e19715585d154464d003759c3a1f4f322 Mon Sep 17 00:00:00 2001 From: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com> Date: Mon, 27 Mar 2023 20:36:59 +0200 Subject: [PATCH] feat(admin-ui, medusa): Improve fulfillment validation (#3541) * validate that an inventory level exists as well * improve create-fulfillment handling in admin * pass along location id rather than inventory level id * add changeset * remove dependency --- .changeset/twelve-queens-hug.md | 6 +++ .../edit-variant-inventory-modal.tsx | 2 +- .../allocations/allocate-items-modal.tsx | 4 +- .../details/create-fulfillment/index.tsx | 1 + .../details/create-fulfillment/item-table.tsx | 48 ++++++++++++++----- .../routes/admin/orders/create-fulfillment.ts | 4 ++ .../src/services/product-variant-inventory.ts | 9 +++- 7 files changed, 58 insertions(+), 16 deletions(-) create mode 100644 .changeset/twelve-queens-hug.md diff --git a/.changeset/twelve-queens-hug.md b/.changeset/twelve-queens-hug.md new file mode 100644 index 0000000000..8b607f2fda --- /dev/null +++ b/.changeset/twelve-queens-hug.md @@ -0,0 +1,6 @@ +--- +"@medusajs/admin-ui": patch +"@medusajs/medusa": patch +--- + +fix(medusa, admin-ui): refine create-fulfillment flow diff --git a/packages/admin-ui/ui/src/components/organisms/product-variants-section/edit-variant-inventory-modal.tsx b/packages/admin-ui/ui/src/components/organisms/product-variants-section/edit-variant-inventory-modal.tsx index bbdd4250f0..20b6f7c2a9 100644 --- a/packages/admin-ui/ui/src/components/organisms/product-variants-section/edit-variant-inventory-modal.tsx +++ b/packages/admin-ui/ui/src/components/organisms/product-variants-section/edit-variant-inventory-modal.tsx @@ -76,7 +76,7 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => { deleteLocations.map(async (location: InventoryLevelDTO) => { await client.admin.inventoryItems.deleteLocationLevel( inventoryItemId!, - location.id + location.location_id ) }) ) diff --git a/packages/admin-ui/ui/src/domain/orders/details/allocations/allocate-items-modal.tsx b/packages/admin-ui/ui/src/domain/orders/details/allocations/allocate-items-modal.tsx index 8e38397ced..77006e603e 100644 --- a/packages/admin-ui/ui/src/domain/orders/details/allocations/allocate-items-modal.tsx +++ b/packages/admin-ui/ui/src/domain/orders/details/allocations/allocate-items-modal.tsx @@ -287,8 +287,8 @@ export const AllocationLineItem: React.FC<{ } )} > -

{availableQuantity || "N/A"} available

-

({inStockQuantity || "N/A"} in stock)

+

{availableQuantity || 0} available

+

({inStockQuantity || 0} in stock)

= ({ value?: string label?: string }>({}) + const [metadata, setMetadata] = useState([ { key: "", value: "" }, ]) diff --git a/packages/admin-ui/ui/src/domain/orders/details/create-fulfillment/item-table.tsx b/packages/admin-ui/ui/src/domain/orders/details/create-fulfillment/item-table.tsx index b18e7fc987..8ca0eebb08 100644 --- a/packages/admin-ui/ui/src/domain/orders/details/create-fulfillment/item-table.tsx +++ b/packages/admin-ui/ui/src/domain/orders/details/create-fulfillment/item-table.tsx @@ -4,6 +4,7 @@ import FeatureToggle from "../../../../components/fundamentals/feature-toggle" import ImagePlaceholder from "../../../../components/fundamentals/image-placeholder" import InputField from "../../../../components/molecules/input" import { LineItem } from "@medusajs/medusa" +import clsx from "clsx" import { useAdminVariantsInventory } from "medusa-react" import { useFeatureFlag } from "../../../../providers/feature-flag-provider" @@ -24,16 +25,20 @@ const CreateFulfillmentItemsTable = ({ locationId: string setErrors: (errors: React.SetStateAction<{}>) => void }) => { - const handleQuantityUpdate = (value: number, id: string) => { - let newQuantities = { ...quantities } + const handleQuantityUpdate = React.useCallback( + (value: number, id: string) => { + let newQuantities = { ...quantities } - newQuantities = { - ...newQuantities, - [id]: value, - } + newQuantities = { + ...newQuantities, + [id]: value, + } + + setQuantities(newQuantities) + }, + [quantities, setQuantities] + ) - setQuantities(newQuantities) - } return (
{items.map((item, idx) => { @@ -118,12 +123,31 @@ const FulfillmentLine = ({ }) }, [validQuantity, setErrors, item.id]) + React.useEffect(() => { + if (!availableQuantity) { + handleQuantityUpdate(0, item.id) + } else { + handleQuantityUpdate( + Math.min(getFulfillableQuantity(item), availableQuantity), + item.id + ) + } + // Note: we can't add handleQuantityUpdate to the dependency array as it will cause an infinite loop + }, [availableQuantity, item, item.id]) + if (getFulfillableQuantity(item) <= 0) { return null } return ( -
+
{item.thumbnail ? ( @@ -148,8 +172,8 @@ const FulfillmentLine = ({
-

{availableQuantity || "N/A"} available

-

({inStockQuantity || "N/A"} in stock)

+

{availableQuantity || 0} available

+

({inStockQuantity || 0} in stock)

} value={quantities[item.id]} - max={getFulfillableQuantity(item)} + max={Math.min(availableQuantity || 0, getFulfillableQuantity(item))} onChange={(e) => handleQuantityUpdate(e.target.valueAsNumber, item.id) } diff --git a/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts b/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts index 27d2063244..8351e7b926 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts @@ -168,7 +168,11 @@ export const updateInventoryAndReservations = async ( items.map(({ item, quantity }) => ({ ...item, quantity } as LineItem)), locationId ) + }) + ) + await Promise.all( + fulfillments.map(async ({ items }) => { await Promise.all( items.map(async ({ item, quantity }) => { if (!item.variant_id) { diff --git a/packages/medusa/src/services/product-variant-inventory.ts b/packages/medusa/src/services/product-variant-inventory.ts index 06f565e51f..b18f736b95 100644 --- a/packages/medusa/src/services/product-variant-inventory.ts +++ b/packages/medusa/src/services/product-variant-inventory.ts @@ -514,12 +514,19 @@ class ProductVariantInventoryService extends TransactionBaseService { for (const item of itemsToValidate) { const pvInventoryItems = await this.listByVariant(item.variant_id!) - const [inventoryLevels] = + const [inventoryLevels, inventoryLevelCount] = await this.inventoryService_.listInventoryLevels({ inventory_item_id: pvInventoryItems.map((i) => i.inventory_item_id), location_id: locationId, }) + if (!inventoryLevelCount) { + throw new MedusaError( + MedusaError.Types.NOT_ALLOWED, + `Inventory item for ${item.title} not found at location` + ) + } + const pviMap: Map = new Map( pvInventoryItems.map((pvi) => [pvi.inventory_item_id, pvi]) )