feat(core-flows, types, medusa): Add Update location level endpoint for api-v2 (#6743)

* initialize update-location-level

* update middlewares

* readd middleware

* pr feedback
This commit is contained in:
Philip Korsholm
2024-03-25 07:43:41 +01:00
committed by GitHub
parent 0168c819da
commit aa154665de
11 changed files with 269 additions and 10 deletions

View File

@@ -6,3 +6,4 @@ export * from "./create-inventory-levels"
export * from "./validate-inventory-locations"
export * from "./update-inventory-items"
export * from "./delete-inventory-levels"
export * from "./update-inventory-levels"

View File

@@ -0,0 +1,57 @@
import { IInventoryServiceNext, InventoryNext } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
import {
convertItemResponseToUpdateRequest,
getSelectsAndRelationsFromObjectArray,
} from "@medusajs/utils"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
export const updateInventoryLevelsStepId = "update-inventory-levels-step"
export const updateInventoryLevelsStep = createStep(
updateInventoryLevelsStepId,
async (
input: InventoryNext.BulkUpdateInventoryLevelInput[],
{ container }
) => {
const inventoryService: IInventoryServiceNext = container.resolve(
ModuleRegistrationName.INVENTORY
)
const { selects, relations } = getSelectsAndRelationsFromObjectArray(input)
const dataBeforeUpdate = await inventoryService.listInventoryLevels(
{
$or: input.map(({ inventory_item_id, location_id }) => ({
inventory_item_id,
location_id,
})),
},
{}
)
const updatedLevels: InventoryNext.InventoryLevelDTO[] =
await inventoryService.updateInventoryLevels(input)
return new StepResponse(updatedLevels, {
dataBeforeUpdate,
selects,
relations,
})
},
async (revertInput, { container }) => {
if (!revertInput?.dataBeforeUpdate?.length) {
return
}
const { dataBeforeUpdate, selects, relations } = revertInput
const inventoryService = container.resolve(ModuleRegistrationName.INVENTORY)
await inventoryService.updateInventoryLevels(
dataBeforeUpdate.map((data) =>
convertItemResponseToUpdateRequest(data, selects, relations)
) as InventoryNext.BulkUpdateInventoryLevelInput[]
)
}
)

View File

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

View File

@@ -0,0 +1,16 @@
import { InventoryLevelDTO, InventoryNext } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { updateInventoryLevelsStep } from "../steps/update-inventory-levels"
interface WorkflowInput {
updates: InventoryNext.BulkUpdateInventoryLevelInput[]
}
export const updateInventoryLevelsWorkflowId =
"update-inventory-levels-workflow"
export const updateInventoryLevelsWorkflow = createWorkflow(
updateInventoryLevelsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<InventoryLevelDTO[]> => {
return updateInventoryLevelsStep(input.updates)
}
)

View File

@@ -5,7 +5,9 @@ import {
} from "@medusajs/utils"
import { MedusaRequest, MedusaResponse } from "../../../../../../types/routing"
import { AdminPostInventoryItemsItemLocationLevelsLevelReq } from "../../../validators"
import { deleteInventoryLevelsWorkflow } from "@medusajs/core-flows"
import { updateInventoryLevelsWorkflow } from "@medusajs/core-flows"
export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
const { id, location_id } = req.params
@@ -45,3 +47,36 @@ export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
deleted: true,
})
}
export const POST = async (
req: MedusaRequest<AdminPostInventoryItemsItemLocationLevelsLevelReq>,
res: MedusaResponse
) => {
const { id: inventory_item_id, location_id } = req.params
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const { errors } = await updateInventoryLevelsWorkflow(req.scope).run({
input: {
updates: [{ inventory_item_id, location_id, ...req.validatedBody }],
},
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const [inventory_item] = await remoteQuery(
remoteQueryObjectFromString({
entryPoint: "inventory",
variables: {
id: inventory_item_id,
},
fields: req.remoteQueryConfig.fields,
})
)
res.status(200).json({
inventory_item,
})
}

View File

@@ -5,6 +5,8 @@ import {
AdminGetInventoryItemsParams,
AdminPostInventoryItemsInventoryItemParams,
AdminPostInventoryItemsInventoryItemReq,
AdminPostInventoryItemsItemLocationLevelsLevelParams,
AdminPostInventoryItemsItemLocationLevelsLevelReq,
AdminPostInventoryItemsItemLocationLevelsReq,
AdminPostInventoryItemsReq,
} from "./validators"
@@ -39,11 +41,6 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
),
],
},
{
method: ["POST"],
matcher: "/admin/inventory-items/:id/location-levels",
middlewares: [transformBody(AdminPostInventoryItemsItemLocationLevelsReq)],
},
{
method: ["POST"],
matcher: "/admin/inventory-items",
@@ -55,6 +52,22 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
),
],
},
{
method: ["POST"],
matcher: "/admin/inventory-items/:id/location-levels",
middlewares: [transformBody(AdminPostInventoryItemsItemLocationLevelsReq)],
},
{
method: ["POST"],
matcher: "/admin/inventory-items/:id/location-levels/:location_id",
middlewares: [
transformBody(AdminPostInventoryItemsItemLocationLevelsLevelReq),
transformQuery(
AdminPostInventoryItemsItemLocationLevelsLevelParams,
QueryConfig.retrieveTransformQueryConfig
),
],
},
{
method: ["POST"],
matcher: "/admin/inventory-items/:id",

View File

@@ -45,6 +45,17 @@ export const retrieveTransformQueryConfig = {
isList: false,
}
export const retrieveLocationLevelsTransformQueryConfig = {
defaults: defaultAdminLocationLevelFields,
allowed: defaultAdminLocationLevelFields,
isList: false,
}
export const listLocationLevelsTransformQueryConfig = {
...retrieveLocationLevelsTransformQueryConfig,
isList: true,
}
export const listTransformQueryConfig = {
...retrieveTransformQueryConfig,
isList: true,

View File

@@ -13,6 +13,7 @@ import {
IsObject,
IsOptional,
IsString,
Min,
ValidateNested,
} from "class-validator"
import { Transform, Type } from "class-transformer"
@@ -258,6 +259,31 @@ export class AdminPostInventoryItemsReq {
metadata?: Record<string, unknown>
}
/**
* @schema AdminPostInventoryItemsItemLocationLevelsLevelReq
* type: object
* properties:
* stocked_quantity:
* description: the total stock quantity of an inventory item at the given location ID
* type: number
* incoming_quantity:
* description: the incoming stock quantity of an inventory item at the given location ID
* type: number
*/
export class AdminPostInventoryItemsItemLocationLevelsLevelReq {
@IsOptional()
@IsNumber()
@Min(0)
incoming_quantity?: number
@IsOptional()
@IsNumber()
@Min(0)
stocked_quantity?: number
}
// eslint-disable-next-line
export class AdminPostInventoryItemsItemLocationLevelsLevelParams extends FindParams {}
/**
* @schema AdminPostInventoryItemsInventoryItemReq
* type: object

View File

@@ -1,3 +1,5 @@
import { BaseFilterable, OperatorMap } from "../../dal"
import { NumericalComparisonOperator } from "../../common"
/**
@@ -53,7 +55,8 @@ export interface InventoryLevelDTO {
deleted_at: string | Date | null
}
export interface FilterableInventoryLevelProps {
export interface FilterableInventoryLevelProps
extends BaseFilterable<FilterableInventoryLevelProps> {
/**
* Filter inventory levels by the ID of their associated inventory item.
*/
@@ -65,13 +68,13 @@ export interface FilterableInventoryLevelProps {
/**
* Filters to apply on inventory levels' `stocked_quantity` attribute.
*/
stocked_quantity?: number | NumericalComparisonOperator
stocked_quantity?: number | OperatorMap<Number>
/**
* Filters to apply on inventory levels' `reserved_quantity` attribute.
*/
reserved_quantity?: number | NumericalComparisonOperator
reserved_quantity?: number | OperatorMap<Number>
/**
* Filters to apply on inventory levels' `incoming_quantity` attribute.
*/
incoming_quantity?: number | NumericalComparisonOperator
incoming_quantity?: number | OperatorMap<Number>
}

View File

@@ -30,7 +30,7 @@ export interface UpdateInventoryLevelInput {
/**
* id of the inventory level to update
*/
id: string
id?: string
/**
* The stocked quantity of the associated inventory item in the associated location.
*/