Feat(core-flows, medusa, types): Add delete location level api-v2 endpoint (#6727)

* add delete inventory level endpoint

* add changeset

* rename step

* rename step
This commit is contained in:
Philip Korsholm
2024-03-19 10:06:37 +01:00
committed by GitHub
parent 390bc3e72f
commit c20eb15cd9
9 changed files with 178 additions and 13 deletions

View File

@@ -0,0 +1,7 @@
---
"@medusajs/core-flows": patch
"@medusajs/medusa": patch
"@medusajs/types": patch
---
feat(medusa, core-flows, types): Add delete-location-level api-v2 endpoints

View File

@@ -229,6 +229,61 @@ medusaIntegrationTestRunner({
)
})
describe("Delete inventory levels", () => {
const locationId = "loc_1"
let inventoryItem
beforeEach(async () => {
inventoryItem = await service.create({
sku: "MY_SKU",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: locationId,
stocked_quantity: 10,
},
])
})
it("should delete an inventory location level without reservations", async () => {
const result = await api.delete(
`/admin/inventory-items/${inventoryItem.id}/location-levels/${locationId}`,
adminHeaders
)
expect(result.status).toEqual(200)
expect(result.data).toEqual({
id: expect.any(String),
object: "inventory-level",
deleted: true,
})
})
it("should fail delete an inventory location level with reservations", async () => {
await service.createReservationItems({
inventory_item_id: inventoryItem.id,
location_id: locationId,
quantity: 5,
})
let error
await api
.delete(
`/admin/inventory-items/${inventoryItem.id}/location-levels/${locationId}`,
adminHeaders
)
.catch((e) => (error = e))
expect(error.response.status).toEqual(400)
expect(error.response.data).toEqual({
type: "not_allowed",
message: `Cannot remove Inventory Level ${inventoryItem.id} at Location ${locationId} because there are reservations at location`,
})
})
})
describe("Retrieve inventory item", () => {
let location1 = "loc_1"
let location2 = "loc_2"

View File

@@ -0,0 +1,29 @@
import { ICustomerModuleService, IInventoryServiceNext } from "@medusajs/types"
import { StepResponse, WorkflowData, createStep } from "@medusajs/workflows-sdk"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
export const deleteInventoryLevelsStepId = "delete-inventory-levels-step"
export const deleteInventoryLevelsStep = createStep(
deleteInventoryLevelsStepId,
async (ids: string[], { container }) => {
const service = container.resolve<IInventoryServiceNext>(
ModuleRegistrationName.INVENTORY
)
await service.softDeleteInventoryLevels(ids)
return new StepResponse(void 0, ids)
},
async (prevLevelIds, { container }) => {
if (!prevLevelIds?.length) {
return
}
const service = container.resolve<IInventoryServiceNext>(
ModuleRegistrationName.INVENTORY
)
await service.restoreInventoryLevels(prevLevelIds)
}
)

View File

@@ -3,3 +3,4 @@ export * from "./create-inventory-items"
export * from "./validate-singular-inventory-items-for-tags"
export * from "./create-inventory-levels"
export * from "./validate-inventory-locations"
export * from "./delete-inventory-levels"

View File

@@ -0,0 +1,15 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { deleteInventoryLevelsStep } from "../steps"
interface WorkflowInput {
ids: string[]
}
export const deleteInventoryLevelsWorkflowId =
"delete-inventory-levels-workflow"
export const deleteInventoryLevelsWorkflow = createWorkflow(
deleteInventoryLevelsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<string[]> => {
return deleteInventoryLevelsStep(input.ids)
}
)

View File

@@ -1,2 +1,3 @@
export * from "./create-inventory-items"
export * from "./create-inventory-levels"
export * from "./delete-inventory-levels"

View File

@@ -0,0 +1,47 @@
import {
ContainerRegistrationKeys,
MedusaError,
remoteQueryObjectFromString,
} from "@medusajs/utils"
import { MedusaRequest, MedusaResponse } from "../../../../../../types/routing"
import { deleteInventoryLevelsWorkflow } from "@medusajs/core-flows"
export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
const { id, location_id } = req.params
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const [{ id: levelId, reserved_quantity: reservedQuantity }] =
await remoteQuery(
remoteQueryObjectFromString({
entryPoint: "inventory_level",
variables: {
inventory_item_id: id,
location_id,
},
fields: ["id", "reserved_quantity"],
})
)
if (reservedQuantity > 0) {
throw new MedusaError(
MedusaError.Types.NOT_ALLOWED,
`Cannot remove Inventory Level ${id} at Location ${location_id} because there are reservations at location`
)
}
const deleteInventoryLevelWorkflow = deleteInventoryLevelsWorkflow(req.scope)
await deleteInventoryLevelWorkflow.run({
input: {
ids: [levelId],
},
})
res.status(200).json({
id: levelId,
object: "inventory-level",
deleted: true,
})
}

View File

@@ -1,19 +1,18 @@
import { InventoryNext } from "@medusajs/types"
// eslint-disable-next-line max-len
export const defaultAdminLocationLevelFields: (keyof InventoryNext.InventoryLevelDTO)[] =
[
"id",
"inventory_item_id",
"location_id",
"stocked_quantity",
"reserved_quantity",
"incoming_quantity",
"available_quantity",
"metadata",
"created_at",
"updated_at",
]
export const defaultAdminLocationLevelFields = [
"id",
"inventory_item_id",
"location_id",
"stocked_quantity",
"reserved_quantity",
"incoming_quantity",
"available_quantity",
"metadata",
"created_at",
"updated_at",
]
export const defaultAdminInventoryItemFields = [
"id",

View File

@@ -795,6 +795,17 @@ export interface IInventoryServiceNext extends IModuleService {
context?: Context
): Promise<void>
softDeleteInventoryLevels<TReturnableLinkableKeys extends string = string>(
inventoryLevelIds: string[],
config?: SoftDeleteReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
restoreInventoryLevels<TReturnableLinkableKeys extends string = string>(
inventoryLevelIds: string[],
config?: RestoreReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
/**
* This method is used to adjust the inventory level's stocked quantity. The inventory level is identified by the IDs of its associated inventory item and location.
*