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:
@@ -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
|
||||||
@@ -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", () => {
|
describe("Retrieve inventory item", () => {
|
||||||
let location1 = "loc_1"
|
let location1 = "loc_1"
|
||||||
let location2 = "loc_2"
|
let location2 = "loc_2"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -3,3 +3,4 @@ export * from "./create-inventory-items"
|
|||||||
export * from "./validate-singular-inventory-items-for-tags"
|
export * from "./validate-singular-inventory-items-for-tags"
|
||||||
export * from "./create-inventory-levels"
|
export * from "./create-inventory-levels"
|
||||||
export * from "./validate-inventory-locations"
|
export * from "./validate-inventory-locations"
|
||||||
|
export * from "./delete-inventory-levels"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from "./create-inventory-items"
|
export * from "./create-inventory-items"
|
||||||
export * from "./create-inventory-levels"
|
export * from "./create-inventory-levels"
|
||||||
|
export * from "./delete-inventory-levels"
|
||||||
|
|||||||
+47
@@ -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,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,19 +1,18 @@
|
|||||||
import { InventoryNext } from "@medusajs/types"
|
import { InventoryNext } from "@medusajs/types"
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
export const defaultAdminLocationLevelFields: (keyof InventoryNext.InventoryLevelDTO)[] =
|
export const defaultAdminLocationLevelFields = [
|
||||||
[
|
"id",
|
||||||
"id",
|
"inventory_item_id",
|
||||||
"inventory_item_id",
|
"location_id",
|
||||||
"location_id",
|
"stocked_quantity",
|
||||||
"stocked_quantity",
|
"reserved_quantity",
|
||||||
"reserved_quantity",
|
"incoming_quantity",
|
||||||
"incoming_quantity",
|
"available_quantity",
|
||||||
"available_quantity",
|
"metadata",
|
||||||
"metadata",
|
"created_at",
|
||||||
"created_at",
|
"updated_at",
|
||||||
"updated_at",
|
]
|
||||||
]
|
|
||||||
|
|
||||||
export const defaultAdminInventoryItemFields = [
|
export const defaultAdminInventoryItemFields = [
|
||||||
"id",
|
"id",
|
||||||
|
|||||||
@@ -795,6 +795,17 @@ export interface IInventoryServiceNext extends IModuleService {
|
|||||||
context?: Context
|
context?: Context
|
||||||
): Promise<void>
|
): 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.
|
* 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.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user