Fix/minor mw fixes (#3521)

**What**
- Fix stock locations quantities being shown as `undefined` and `NaN`
- Throw if updates to location levels are made with negative quantities through the api
- Show "allocated" in order summary for partially fulfilled orders

Fixes CORE-1268, CORE-1267, CORE-1265
This commit is contained in:
Philip Korsholm
2023-03-19 20:28:59 +00:00
committed by GitHub
parent a3a7ace0c0
commit ea2633bccf
5 changed files with 53 additions and 12 deletions
@@ -207,6 +207,40 @@ describe("Inventory Items endpoints", () => {
) )
}) })
it.only("fails to update location level to negative quantity", async () => {
const api = useApi()
const inventoryItemId = inventoryItems[0].id
await api.post(
`/admin/inventory-items/${inventoryItemId}/location-levels`,
{
location_id: locationId,
stocked_quantity: 17,
incoming_quantity: 2,
},
adminHeaders
)
const res = await api
.post(
`/admin/inventory-items/${inventoryItemId}/location-levels/${locationId}`,
{
incoming_quantity: -1,
stocked_quantity: -1,
},
adminHeaders
)
.catch((error) => error)
expect(res.response.status).toEqual(400)
expect(res.response.data).toEqual({
type: "invalid_data",
message:
"incoming_quantity must not be less than 0, stocked_quantity must not be less than 0",
})
})
it("Retrieve an inventory item", async () => { it("Retrieve an inventory item", async () => {
const api = useApi() const api = useApi()
const inventoryItemId = inventoryItems[0].id const inventoryItemId = inventoryItems[0].id
@@ -456,6 +456,8 @@ const AdjustAvailabilityModal = ({
onChange={(e) => setStockedQuantity(e.target.valueAsNumber)} onChange={(e) => setStockedQuantity(e.target.valueAsNumber)}
autoFocus autoFocus
type="number" type="number"
placeholder="0"
min={0}
value={stockedQuantity} value={stockedQuantity}
/> />
</div> </div>
@@ -56,7 +56,8 @@ const SummaryCard: React.FC<SummaryCardProps> = ({ order, reservations }) => {
return ( return (
item.quantity === item.fulfilled_quantity || item.quantity === item.fulfilled_quantity ||
(reservations && (reservations &&
sum(reservations.map((r) => r.quantity)) === item.quantity) sum(reservations.map((r) => r.quantity)) ===
item.quantity - (item.fulfilled_quantity || 0))
) )
}) })
}, [reservationItemsMap, order]) }, [reservationItemsMap, order])
@@ -1,15 +1,16 @@
import React, { useMemo, useState, useContext } from "react"
import Modal from "../../../../../components/molecules/modal"
import { LayeredModalContext } from "../../../../../components/molecules/modal/layered-modal"
import { useAdminStockLocations } from "medusa-react"
import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/medusa"
import { Controller, useFieldArray } from "react-hook-form" import { Controller, useFieldArray } from "react-hook-form"
import Button from "../../../../../components/fundamentals/button" import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/medusa"
import Switch from "../../../../../components/atoms/switch" import React, { useContext, useMemo, useState } from "react"
import InputField from "../../../../../components/molecules/input"
import { NestedForm } from "../../../../../utils/nested-form"
import IconBadge from "../../../../../components/fundamentals/icon-badge"
import BuildingsIcon from "../../../../../components/fundamentals/icons/buildings-icon" import BuildingsIcon from "../../../../../components/fundamentals/icons/buildings-icon"
import Button from "../../../../../components/fundamentals/button"
import IconBadge from "../../../../../components/fundamentals/icon-badge"
import InputField from "../../../../../components/molecules/input"
import { LayeredModalContext } from "../../../../../components/molecules/modal/layered-modal"
import Modal from "../../../../../components/molecules/modal"
import { NestedForm } from "../../../../../utils/nested-form"
import Switch from "../../../../../components/atoms/switch"
import { useAdminStockLocations } from "medusa-react"
export type VariantStockFormType = { export type VariantStockFormType = {
manage_inventory?: boolean manage_inventory?: boolean
@@ -64,6 +65,7 @@ const VariantStockForm = ({ form, locationLevels }: Props) => {
append({ append({
location_id: added, location_id: added,
stocked_quantity: locationLevelMap.get(added)?.stocked_quantity ?? 0, stocked_quantity: locationLevelMap.get(added)?.stocked_quantity ?? 0,
reserved_quantity: locationLevelMap.get(added)?.reserved_quantity ?? 0,
}) })
}) })
} }
@@ -1,5 +1,5 @@
import { Request, Response } from "express" import { Request, Response } from "express"
import { IsNumber, IsOptional } from "class-validator" import { IsNumber, IsOptional, Min } from "class-validator"
import { IInventoryService } from "../../../../interfaces" import { IInventoryService } from "../../../../interfaces"
import { FindParams } from "../../../../types/common" import { FindParams } from "../../../../types/common"
@@ -105,10 +105,12 @@ export default async (req: Request, res: Response) => {
export class AdminPostInventoryItemsItemLocationLevelsLevelReq { export class AdminPostInventoryItemsItemLocationLevelsLevelReq {
@IsOptional() @IsOptional()
@IsNumber() @IsNumber()
@Min(0)
incoming_quantity?: number incoming_quantity?: number
@IsOptional() @IsOptional()
@IsNumber() @IsNumber()
@Min(0)
stocked_quantity?: number stocked_quantity?: number
} }