feat(medusa, inventory): Inventory Management module (#2956)

* feat: inventory module
This commit is contained in:
Carlos R. L. Rodrigues authored and GitHub committed 2023-01-10 14:38:30 -03:00
1 parent a2df11fc10
commit 93ee248493
22 files changed
+1735 -14

No files matched your search

@@ -31,12 +31,12 @@ export interface IInventoryService {
): Promise<[InventoryLevelDTO[], number]>
retrieveInventoryItem(
itemId: string,
inventoryItemId: string,
config?: FindConfig<InventoryItemDTO>
): Promise<InventoryItemDTO>
retrieveInventoryLevel(
itemId: string,
inventoryItemId: string,
locationId: string
): Promise<InventoryLevelDTO>
@@ -53,48 +53,56 @@ export interface IInventoryService {
): Promise<InventoryLevelDTO>
updateInventoryLevel(
itemId: string,
inventoryItemId: string,
locationId: string,
update: UpdateInventoryLevelInput
): Promise<InventoryLevelDTO>
updateInventoryItem(
itemId: string,
inventoryItemId: string,
input: CreateInventoryItemInput
): Promise<InventoryItemDTO>
updateReservationItem(
reservationId: string,
update: UpdateReservationItemInput
reservationItemId: string,
input: UpdateReservationItemInput
): Promise<ReservationItemDTO>
deleteReservationItemsByLineItem(lineItemId: string): Promise<void>
deleteReservationItem(id: string): Promise<void>
deleteReservationItem(reservationItemId: string): Promise<void>
deleteInventoryItem(itemId: string): Promise<void>
deleteInventoryItem(inventoryItemId: string): Promise<void>
deleteInventoryLevel(itemId: string, locationId: string): Promise<void>
deleteInventoryLevel(
inventoryLevelId: string,
locationId: string
): Promise<void>
adjustInventory(
itemId: string,
inventoryItemId: string,
locationId: string,
adjustment: number
): Promise<InventoryLevelDTO>
confirmInventory(
itemId: string,
inventoryItemId: string,
locationIds: string[],
quantity: number
): Promise<boolean>
retrieveAvailableQuantity(
itemId: string,
inventoryItemId: string,
locationIds: string[]
): Promise<number>
retrieveStockedQuantity(
itemId: string,
inventoryItemId: string,
locationIds: string[]
): Promise<number>
retrieveReservedQuantity(
inventoryItemId: string,
locationIds: string[]
): Promise<number>
}
@@ -0,0 +1,128 @@
import dotenv from "dotenv"
import { AwilixContainer } from "awilix"
import express from "express"
import {
ProductVariantService,
ProductVariantInventoryService,
} from "../services"
import { ProductVariant } from "../models"
import { IInventoryService, IStockLocationService } from "../interfaces"
import loaders from "../loaders"
dotenv.config()
const BATCH_SIZE = 100
const migrateProductVariant = async (
variant: ProductVariant,
locationId: string,
{ container }: { container: AwilixContainer }
) => {
const productVariantInventoryService: ProductVariantInventoryService =
container.resolve("productVariantInventoryService")
const inventoryService: IInventoryService =
container.resolve("inventoryService")
if (!variant.manage_inventory) {
return
}
const inventoryItem = await inventoryService.createInventoryItem({
sku: variant.sku,
material: variant.material,
width: variant.width,
length: variant.length,
height: variant.height,
weight: variant.weight,
origin_country: variant.origin_country,
hs_code: variant.hs_code,
mid_code: variant.mid_code,
requires_shipping: true,
})
await productVariantInventoryService.attachInventoryItem(
variant.id,
inventoryItem.id,
1
)
await inventoryService.createInventoryLevel({
location_id: locationId,
inventory_item_id: inventoryItem.id,
stocked_quantity: variant.inventory_quantity,
incoming_quantity: 0,
})
}
const migrateStockLocation = async (container: AwilixContainer) => {
const stockLocationService: IStockLocationService = container.resolve(
"stockLocationService"
)
const existing = await stockLocationService.list({}, { take: 1 })
if (existing.length) {
return existing[0].id
}
const stockLocation = await stockLocationService.create({ name: "Default" })
return stockLocation.id
}
const processBatch = async (
variants: ProductVariant[],
locationId: string,
container: AwilixContainer
) => {
await Promise.all(
variants.map(async (variant) => {
await migrateProductVariant(variant, locationId, { container })
})
)
}
const migrate = async function ({ directory }) {
const app = express()
const { container } = await loaders({
directory,
expressApp: app,
isTest: false,
})
const variantService: ProductVariantService = await container.resolve(
"productVariantService"
)
const defaultLocationId = await migrateStockLocation(container)
const [variants, totalCount] = await variantService.listAndCount(
{},
{ take: BATCH_SIZE, order: { id: "ASC" } }
)
await processBatch(variants, defaultLocationId, container)
let processedCount = variants.length
console.log(`Processed ${processedCount} of ${totalCount}`)
while (processedCount < totalCount) {
const nextBatch = await variantService.list(
{},
{
skip: processedCount,
take: BATCH_SIZE,
order: { id: "ASC" },
}
)
await processBatch(nextBatch, defaultLocationId, container)
processedCount += nextBatch.length
console.log(`Processed ${processedCount} of ${totalCount}`)
}
console.log("Done")
process.exit(0)
}
migrate({ directory: process.cwd() })
+4 -1
View File
@@ -34,6 +34,7 @@ export type InventoryLevelDTO = {
inventory_item_id: string
location_id: string
stocked_quantity: number
reserved_quantity: number
incoming_quantity: number
metadata: Record<string, unknown> | null
created_at: string | Date
@@ -87,6 +88,7 @@ export type FilterableInventoryLevelProps = {
inventory_item_id?: string | string[]
location_id?: string | string[]
stocked_quantity?: number | NumericalComparisonOperator
reserved_quantity?: number | NumericalComparisonOperator
incoming_quantity?: number | NumericalComparisonOperator
}
@@ -94,7 +96,8 @@ export type CreateInventoryLevelInput = {
inventory_item_id: string
location_id: string
stocked_quantity: number
incoming_quantity: number
reserved_quantity?: number
incoming_quantity?: number
}
export type UpdateInventoryLevelInput = {