feat(inventory-next, types): inventory module conversion (#6596)

* init

* create new interface

* prep integration tests

* update denpencies

* inventory service partial tests

* finalize integration tests

* add events

* align events

* adjust inventory level reservation levels

* add test validating reserved quantity after reseration item update

* fix nits

* rename to inventory-next

* update yarn.lock

* remove changelog

* remove fixtures

* remove unused files

* ready for review

* Update packages/inventory-next/package.json

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>

* pr feedback

* add tests and docs for partition-array util

* remote decorators from private method

* fix unit tests

* add migrations

* add foreign keys

* fix build

---------

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Philip Korsholm
2024-03-08 14:09:05 +01:00
committed by GitHub
parent 8406eb5a35
commit c19d276458
46 changed files with 4896 additions and 14 deletions

6
packages/inventory-next/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
/dist
node_modules
.DS_store
.env*
.env
*.sql

View File

@@ -0,0 +1,873 @@
import { IInventoryServiceNext, InventoryItemDTO } from "@medusajs/types"
import { SuiteOptions, moduleIntegrationTestRunner } from "medusa-test-utils"
import { Modules } from "@medusajs/modules-sdk"
jest.setTimeout(100000)
moduleIntegrationTestRunner({
moduleName: Modules.INVENTORY,
resolve: "@medusajs/inventory-next",
testSuite: ({
MikroOrmWrapper,
service,
}: SuiteOptions<IInventoryServiceNext>) => {
describe("Inventory Module Service", () => {
describe("create", () => {
it("should create an inventory item", async () => {
const data = { sku: "test-sku", origin_country: "test-country" }
const inventoryItem = await service.create(data)
expect(inventoryItem).toEqual(
expect.objectContaining({ id: expect.any(String), ...data })
)
})
it("should create inventory items from array", async () => {
const data = [
{ sku: "test-sku", origin_country: "test-country" },
{ sku: "test-sku-1", origin_country: "test-country-1" },
]
const inventoryItems = await service.create(data)
expect(inventoryItems).toEqual([
expect.objectContaining({ id: expect.any(String), ...data[0] }),
expect.objectContaining({ id: expect.any(String), ...data[1] }),
])
})
})
describe("createReservationItem", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 2,
},
])
})
it("should create a reservationItem", async () => {
const data = {
inventory_item_id: inventoryItem.id,
location_id: "location-1",
quantity: 2,
}
const reservationItem = await service.createReservationItems(data)
expect(reservationItem).toEqual(
expect.objectContaining({ id: expect.any(String), ...data })
)
})
it("should create adjust reserved_quantity of inventory level after creation", async () => {
await service.createReservationItems({
inventory_item_id: inventoryItem.id,
location_id: "location-1",
quantity: 2,
})
const inventoryLevel =
await service.retrieveInventoryLevelByItemAndLocation(
inventoryItem.id,
"location-1"
)
expect(inventoryLevel.reserved_quantity).toEqual(2)
})
it("should create reservationItems from array", async () => {
const data = [
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
quantity: 3,
},
]
const reservationItems = await service.createReservationItems(data)
expect(reservationItems).toEqual([
expect.objectContaining({ id: expect.any(String), ...data[0] }),
expect.objectContaining({ id: expect.any(String), ...data[1] }),
])
})
it("should fail to create a reservationItem for a non-existing location", async () => {
const data = [
{
inventory_item_id: inventoryItem.id,
location_id: "location-3",
quantity: 2,
},
]
const err = await service
.createReservationItems(data)
.catch((error) => error)
expect(err.message).toEqual(
`Item ${inventoryItem.id} is not stocked at location location-3`
)
})
})
describe("createInventoryLevel", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
})
it("should create an inventoryLevel", async () => {
const data = {
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
}
const inventoryLevel = await service.createInventoryLevels(data)
expect(inventoryLevel).toEqual(
expect.objectContaining({ id: expect.any(String), ...data })
)
})
it("should create inventoryLevels from array", async () => {
const data = [
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 3,
},
]
const inventoryLevels = await service.createInventoryLevels(data)
expect(inventoryLevels).toEqual([
expect.objectContaining({ id: expect.any(String), ...data[0] }),
expect.objectContaining({ id: expect.any(String), ...data[1] }),
])
})
})
describe("update", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
})
it("should update the inventory item", async () => {
const update = {
id: inventoryItem.id,
sku: "updated-sku",
}
const updated = await service.update(update)
expect(updated).toEqual(expect.objectContaining(update))
})
it("should update multiple inventory items", async () => {
const item2 = await service.create({
sku: "test-sku-1",
})
const updates = [
{
id: inventoryItem.id,
sku: "updated-sku",
},
{
id: item2.id,
sku: "updated-sku-2",
},
]
const updated = await service.update(updates)
expect(updated).toEqual([
expect.objectContaining(updates[0]),
expect.objectContaining(updates[1]),
])
})
})
describe("updateInventoryLevels", () => {
let inventoryLevel
let inventoryItem
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
const data = {
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
}
inventoryLevel = await service.createInventoryLevels(data)
})
it("should update inventory level", async () => {
const updatedLevel = await service.updateInventoryLevels({
location_id: "location-1",
inventory_item_id: inventoryItem.id,
incoming_quantity: 4,
})
expect(updatedLevel.incoming_quantity).toEqual(4)
})
it("should fail to update inventory level for item in location that isn't stocked", async () => {
const error = await service
.updateInventoryLevels({
inventory_item_id: inventoryItem.id,
location_id: "does-not-exist",
stocked_quantity: 10,
})
.catch((error) => error)
expect(error.message).toEqual(
`Item ${inventoryItem.id} is not stocked at location does-not-exist`
)
})
})
describe("updateReservationItems", () => {
let reservationItem
beforeEach(async () => {
const inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 2,
},
])
reservationItem = await service.createReservationItems({
inventory_item_id: inventoryItem.id,
location_id: "location-1",
quantity: 2,
})
})
it("should update a reservationItem", async () => {
const update = {
id: reservationItem.id,
quantity: 5,
}
const updated = await service.updateReservationItems(update)
expect(updated).toEqual(expect.objectContaining(update))
})
it("should adjust reserved_quantity of inventory level after updates increasing reserved quantity", async () => {
const update = {
id: reservationItem.id,
quantity: 5,
}
await service.updateReservationItems(update)
const inventoryLevel =
await service.retrieveInventoryLevelByItemAndLocation(
reservationItem.inventory_item_id,
"location-1"
)
expect(inventoryLevel.reserved_quantity).toEqual(update.quantity)
})
it("should adjust reserved_quantity of inventory level after updates decreasing reserved quantity", async () => {
const update = {
id: reservationItem.id,
quantity: 1,
}
await service.updateReservationItems(update)
const inventoryLevel =
await service.retrieveInventoryLevelByItemAndLocation(
reservationItem.inventory_item_id,
"location-1"
)
expect(inventoryLevel.reserved_quantity).toEqual(update.quantity)
})
})
describe("deleteReservationItemsByLineItem", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 2,
},
])
await service.createReservationItems([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
quantity: 2,
line_item_id: "line-item-id",
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
quantity: 2,
line_item_id: "line-item-id",
},
])
})
it("deleted reseravation items by line item", async () => {
const reservationsPreDeleted = await service.listReservationItems({
line_item_id: "line-item-id",
})
expect(reservationsPreDeleted).toEqual([
expect.objectContaining({
location_id: "location-1",
quantity: 2,
line_item_id: "line-item-id",
}),
expect.objectContaining({
location_id: "location-1",
quantity: 2,
line_item_id: "line-item-id",
}),
])
await service.deleteReservationItemsByLineItem("line-item-id")
const reservationsPostDeleted = await service.listReservationItems({
line_item_id: "line-item-id",
})
expect(reservationsPostDeleted).toEqual([])
})
it("adjusts inventory levels accordingly when removing reservations by line item", async () => {
await service.deleteReservationItemsByLineItem("line-item-id")
const inventoryLevel =
await service.retrieveInventoryLevelByItemAndLocation(
inventoryItem.id,
"location-1"
)
expect(inventoryLevel).toEqual(
expect.objectContaining({ reserved_quantity: 2 })
)
})
})
describe("deleteReservationItemByLocationId", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 2,
},
])
await service.createReservationItems([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
quantity: 2,
line_item_id: "line-item-id",
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
quantity: 2,
line_item_id: "line-item-id",
},
])
})
it("deleted reservation items by line item", async () => {
const reservationsPreDeleted = await service.listReservationItems({
location_id: "location-1",
})
expect(reservationsPreDeleted).toEqual([
expect.objectContaining({
location_id: "location-1",
quantity: 2,
}),
expect.objectContaining({
location_id: "location-1",
quantity: 2,
}),
])
await service.deleteReservationItemByLocationId("location-1")
const reservationsPostDeleted = await service.listReservationItems({
location_id: "location-1",
})
expect(reservationsPostDeleted).toEqual([])
})
it("adjusts inventory levels accordingly when removing reservations by line item", async () => {
const inventoryLevelPreDelete =
await service.retrieveInventoryLevelByItemAndLocation(
inventoryItem.id,
"location-1"
)
expect(inventoryLevelPreDelete).toEqual(
expect.objectContaining({ reserved_quantity: 4 })
)
await service.deleteReservationItemByLocationId("location-1")
const inventoryLevel =
await service.retrieveInventoryLevelByItemAndLocation(
inventoryItem.id,
"location-1"
)
expect(inventoryLevel).toEqual(
expect.objectContaining({ reserved_quantity: 0 })
)
})
})
describe("deleteInventoryItemLevelByLocationId", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
reserved_quantity: 6,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 2,
},
])
})
it("should remove inventory levels with given location id", async () => {
const inventoryLevelsPreDeletion = await service.listInventoryLevels(
{}
)
expect(inventoryLevelsPreDeletion).toEqual(
expect.arrayContaining([
expect.objectContaining({
stocked_quantity: 2,
location_id: "location-1",
}),
expect.objectContaining({
stocked_quantity: 2,
location_id: "location-2",
}),
])
)
await service.deleteInventoryItemLevelByLocationId("location-1")
const inventoryLevelsPostDeletion = await service.listInventoryLevels(
{}
)
expect(inventoryLevelsPostDeletion).toEqual([
expect.objectContaining({
stocked_quantity: 2,
location_id: "location-2",
}),
])
})
})
describe("deleteInventoryLevel", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
},
])
})
it("should remove inventory levels with given location id", async () => {
const inventoryLevelsPreDeletion = await service.listInventoryLevels(
{}
)
expect(inventoryLevelsPreDeletion).toEqual([
expect.objectContaining({
stocked_quantity: 2,
location_id: "location-1",
}),
])
await service.deleteInventoryLevel(inventoryItem.id, "location-1")
const inventoryLevelsPostDeletion = await service.listInventoryLevels(
{}
)
expect(inventoryLevelsPostDeletion).toEqual([])
})
})
describe("adjustInventory", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
},
])
})
it("should updated inventory level stocked_quantity by quantity", async () => {
const updatedLevel = await service.adjustInventory(
inventoryItem.id,
"location-1",
2
)
expect(updatedLevel.stocked_quantity).toEqual(4)
})
it("should updated inventory level stocked_quantity by negative quantity", async () => {
const updatedLevel = await service.adjustInventory(
inventoryItem.id,
"location-1",
-1
)
expect(updatedLevel.stocked_quantity).toEqual(1!)
})
})
describe("retrieveInventoryLevelByItemAndLocation", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
const inventoryItem1 = await service.create({
sku: "test-sku-1",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 3,
},
{
inventory_item_id: inventoryItem1.id,
location_id: "location-1",
stocked_quantity: 3,
},
])
})
it("should retrieve inventory level with provided location_id and inventory_item", async () => {
const level = await service.retrieveInventoryLevelByItemAndLocation(
inventoryItem.id,
"location-1"
)
expect(level.stocked_quantity).toEqual(2)
})
})
describe("retrieveAvailableQuantity", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
const inventoryItem1 = await service.create({
sku: "test-sku-1",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 4,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 4,
reserved_quantity: 2,
},
{
inventory_item_id: inventoryItem1.id,
location_id: "location-1",
stocked_quantity: 3,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-3",
stocked_quantity: 3,
},
])
})
it("should calculate current stocked quantity across locations", async () => {
const level = await service.retrieveAvailableQuantity(
inventoryItem.id,
["location-1", "location-2"]
)
expect(level).toEqual(6)
})
})
describe("retrieveStockedQuantity", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
const inventoryItem1 = await service.create({
sku: "test-sku-1",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 4,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 4,
reserved_quantity: 2,
},
{
inventory_item_id: inventoryItem1.id,
location_id: "location-1",
stocked_quantity: 3,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-3",
stocked_quantity: 3,
},
])
})
it("retrieves stocked location", async () => {
const stockedQuantity = await service.retrieveStockedQuantity(
inventoryItem.id,
["location-1", "location-2"]
)
expect(stockedQuantity).toEqual(8)
})
})
describe("retrieveReservedQuantity", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
const inventoryItem1 = await service.create({
sku: "test-sku-1",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 4,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 4,
reserved_quantity: 2,
},
{
inventory_item_id: inventoryItem1.id,
location_id: "location-1",
stocked_quantity: 3,
reserved_quantity: 2,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-3",
stocked_quantity: 3,
reserved_quantity: 2,
},
])
})
it("retrieves reserved quantity", async () => {
const reservedQuantity = await service.retrieveReservedQuantity(
inventoryItem.id,
["location-1", "location-2"]
)
expect(reservedQuantity).toEqual(2)
})
})
describe("confirmInventory", () => {
let inventoryItem: InventoryItemDTO
beforeEach(async () => {
inventoryItem = await service.create({
sku: "test-sku",
origin_country: "test-country",
})
await service.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: "location-1",
stocked_quantity: 4,
},
{
inventory_item_id: inventoryItem.id,
location_id: "location-2",
stocked_quantity: 4,
reserved_quantity: 2,
},
])
})
it("should return true if quantity is less than or equal to available quantity", async () => {
const reservedQuantity = await service.confirmInventory(
inventoryItem.id,
"location-1",
2
)
expect(reservedQuantity).toBeTruthy()
})
it("should return true if quantity is more than available quantity", async () => {
const reservedQuantity = await service.confirmInventory(
inventoryItem.id,
"location-1",
3
)
expect(reservedQuantity).toBeTruthy()
})
})
})
},
})

View File

@@ -0,0 +1,13 @@
module.exports = {
transform: {
"^.+\\.[jt]s?$": [
"ts-jest",
{
tsConfig: "tsconfig.json",
isolatedModules: true,
},
],
},
testEnvironment: `node`,
moduleFileExtensions: [`js`, `ts`],
}

View File

@@ -0,0 +1,13 @@
import * as entities from "./src/models"
import { TSMigrationGenerator } from "@medusajs/utils"
module.exports = {
entities: Object.values(entities),
schema: "public",
clientUrl: "postgres://postgres@localhost/medusa-inventory",
type: "postgresql",
migrations: {
generator: TSMigrationGenerator,
},
}

View File

@@ -0,0 +1,58 @@
{
"name": "@medusajs/inventory-next",
"version": "0.0.1",
"description": "Inventory Module for Medusa",
"main": "dist/index.js",
"repository": {
"type": "git",
"url": "https://github.com/medusajs/medusa",
"directory": "packages/inventory-next"
},
"publishConfig": {
"access": "public"
},
"files": [
"dist"
],
"engines": {
"node": ">=16"
},
"author": "Medusa",
"license": "MIT",
"devDependencies": {
"@medusajs/types": "^1.11.12",
"@mikro-orm/cli": "5.9.7",
"cross-env": "^5.2.1",
"jest": "^29.6.3",
"medusa-test-utils": "^1.1.40",
"rimraf": "^5.0.1",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"tsc-alias": "^1.8.6",
"typescript": "^5.1.6"
},
"dependencies": {
"@medusajs/modules-sdk": "^1.12.4",
"@medusajs/types": "^1.11.8",
"@medusajs/utils": "^1.11.1",
"@mikro-orm/core": "5.9.7",
"@mikro-orm/migrations": "5.9.7",
"@mikro-orm/postgresql": "5.9.7",
"awilix": "^8.0.0",
"dotenv": "16.4.5",
"knex": "2.4.2"
},
"scripts": {
"watch": "tsc --build --watch",
"watch:test": "tsc --build tsconfig.spec.json --watch",
"prepublishOnly": "cross-env NODE_ENV=production tsc --build && tsc-alias -p tsconfig.json",
"build": "rimraf dist && tsc --build && tsc-alias -p tsconfig.json",
"test": "jest --runInBand --bail --forceExit -- src/**/__tests__/**/*.ts",
"test:integration": "jest --runInBand --forceExit -- integration-tests/**/__tests__/**/*.spec.ts",
"migration:generate": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:generate",
"migration:initial": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create --initial -n InitialSetupMigration",
"migration:create": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create",
"migration:up": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:up",
"orm:cache:clear": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm cache:clear"
}
}

View File

@@ -0,0 +1,14 @@
import { Modules, initializeFactory } from "@medusajs/modules-sdk"
import { moduleDefinition } from "./module-definition"
export * from "./models"
export * from "./services"
export const initialize = initializeFactory({
moduleName: Modules.INVENTORY,
moduleDefinition,
})
export const runMigrations = moduleDefinition.runMigrations
export const revertMigration = moduleDefinition.revertMigration
export default moduleDefinition

View File

@@ -0,0 +1,60 @@
import { InventoryItem, InventoryLevel, ReservationItem } from "./models"
import { MapToConfig } from "@medusajs/utils"
import { ModuleJoinerConfig } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk"
import moduleSchema from "./schema"
export const LinkableKeys = {
inventory_item_id: InventoryItem.name,
inventory_level_id: InventoryLevel.name,
reservation_item_id: ReservationItem.name,
}
const entityLinkableKeysMap: MapToConfig = {}
Object.entries(LinkableKeys).forEach(([key, value]) => {
entityLinkableKeysMap[value] ??= []
entityLinkableKeysMap[value].push({
mapTo: key,
valueFrom: key.split("_").pop()!,
})
})
export const entityNameToLinkableKeysMap: MapToConfig = entityLinkableKeysMap
export const joinerConfig: ModuleJoinerConfig = {
serviceName: Modules.INVENTORY,
primaryKeys: ["id"],
linkableKeys: {
inventory_item_id: InventoryItem.name,
inventory_level_id: InventoryLevel.name,
reservation_item_id: ReservationItem.name,
},
schema: moduleSchema,
alias: [
{
name: ["inventory_items", "inventory"],
args: {
entity: "InventoryItem",
},
},
{
name: ["inventory_level", "inventory_levels"],
args: {
entity: "InventoryLevel",
methodSuffix: "InventoryLevels",
},
},
{
name: [
"reservation",
"reservations",
"reservation_item",
"reservation_items",
],
args: {
entity: "ReservationItem",
methodSuffix: "ReservationItems",
},
},
],
}

View File

@@ -0,0 +1,570 @@
{
"namespaces": [
"public"
],
"name": "public",
"tables": [
{
"columns": {
"id": {
"name": "id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"created_at": {
"name": "created_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
},
"updated_at": {
"name": "updated_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
},
"deleted_at": {
"name": "deleted_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"length": 6,
"mappedType": "datetime"
},
"sku": {
"name": "sku",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"origin_country": {
"name": "origin_country",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"hs_code": {
"name": "hs_code",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"mid_code": {
"name": "mid_code",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"material": {
"name": "material",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"weight": {
"name": "weight",
"type": "int",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "integer"
},
"length": {
"name": "length",
"type": "int",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "integer"
},
"height": {
"name": "height",
"type": "int",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "integer"
},
"width": {
"name": "width",
"type": "int",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "integer"
},
"requires_shipping": {
"name": "requires_shipping",
"type": "boolean",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"default": "true",
"mappedType": "boolean"
},
"description": {
"name": "description",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"title": {
"name": "title",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"thumbnail": {
"name": "thumbnail",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"metadata": {
"name": "metadata",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
}
},
"name": "inventory_item",
"schema": "public",
"indexes": [
{
"keyName": "IDX_inventory_item_deleted_at",
"columnNames": [
"deleted_at"
],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_inventory_item_deleted_at\" ON \"inventory_item\" (deleted_at) WHERE deleted_at IS NOT NULL"
},
{
"keyName": "IDX_inventory_item_sku_unique",
"columnNames": [
"sku"
],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_inventory_item_sku_unique\" ON \"inventory_item\" (sku)"
},
{
"keyName": "inventory_item_pkey",
"columnNames": [
"id"
],
"composite": false,
"primary": true,
"unique": true
}
],
"checks": [],
"foreignKeys": {}
},
{
"columns": {
"id": {
"name": "id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"created_at": {
"name": "created_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
},
"updated_at": {
"name": "updated_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
},
"deleted_at": {
"name": "deleted_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"length": 6,
"mappedType": "datetime"
},
"inventory_item_id": {
"name": "inventory_item_id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"location_id": {
"name": "location_id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"stocked_quantity": {
"name": "stocked_quantity",
"type": "int",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"default": "0",
"mappedType": "integer"
},
"reserved_quantity": {
"name": "reserved_quantity",
"type": "int",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"default": "0",
"mappedType": "integer"
},
"incoming_quantity": {
"name": "incoming_quantity",
"type": "int",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"default": "0",
"mappedType": "integer"
},
"metadata": {
"name": "metadata",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
}
},
"name": "inventory_level",
"schema": "public",
"indexes": [
{
"keyName": "IDX_inventory_level_deleted_at",
"columnNames": [
"deleted_at"
],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_inventory_level_deleted_at\" ON \"inventory_level\" (deleted_at) WHERE deleted_at IS NOT NULL"
},
{
"keyName": "IDX_inventory_level_inventory_item_id",
"columnNames": [
"inventory_item_id"
],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_inventory_level_inventory_item_id\" ON \"inventory_level\" (inventory_item_id)"
},
{
"keyName": "IDX_inventory_level_location_id",
"columnNames": [
"location_id"
],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_inventory_level_location_id\" ON \"inventory_level\" (location_id)"
},
{
"keyName": "IDX_inventory_level_location_id",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_inventory_level_location_id\" ON \"inventory_level\" (location_id)"
},
{
"keyName": "inventory_level_pkey",
"columnNames": [
"id"
],
"composite": false,
"primary": true,
"unique": true
}
],
"checks": [],
"foreignKeys": {
"inventory_level_inventory_item_id_foreign": {
"constraintName": "inventory_level_inventory_item_id_foreign",
"columnNames": [
"inventory_item_id"
],
"localTableName": "public.inventory_level",
"referencedColumnNames": [
"id"
],
"referencedTableName": "public.inventory_item",
"deleteRule": "cascade",
"updateRule": "cascade"
}
}
},
{
"columns": {
"id": {
"name": "id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"created_at": {
"name": "created_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
},
"updated_at": {
"name": "updated_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
},
"deleted_at": {
"name": "deleted_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"length": 6,
"mappedType": "datetime"
},
"line_item_id": {
"name": "line_item_id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"location_id": {
"name": "location_id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"quantity": {
"name": "quantity",
"type": "integer",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "integer"
},
"external_id": {
"name": "external_id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"description": {
"name": "description",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"created_by": {
"name": "created_by",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"metadata": {
"name": "metadata",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"inventory_item_id": {
"name": "inventory_item_id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
}
},
"name": "reservation_item",
"schema": "public",
"indexes": [
{
"keyName": "IDX_reservation_item_deleted_at",
"columnNames": [
"deleted_at"
],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_reservation_item_deleted_at\" ON \"reservation_item\" (deleted_at) WHERE deleted_at IS NOT NULL"
},
{
"keyName": "IDX_reservation_item_line_item_id",
"columnNames": [
"line_item_id"
],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_reservation_item_line_item_id\" ON \"reservation_item\" (line_item_id)"
},
{
"keyName": "IDX_reservation_item_location_id",
"columnNames": [
"location_id"
],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_reservation_item_location_id\" ON \"reservation_item\" (location_id)"
},
{
"keyName": "IDX_reservation_item_inventory_item_id",
"columnNames": [
"inventory_item_id"
],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_reservation_item_inventory_item_id\" ON \"reservation_item\" (inventory_item_id)"
},
{
"keyName": "reservation_item_pkey",
"columnNames": [
"id"
],
"composite": false,
"primary": true,
"unique": true
}
],
"checks": [],
"foreignKeys": {
"reservation_item_inventory_item_id_foreign": {
"constraintName": "reservation_item_inventory_item_id_foreign",
"columnNames": [
"inventory_item_id"
],
"localTableName": "public.reservation_item",
"referencedColumnNames": [
"id"
],
"referencedTableName": "public.inventory_item",
"deleteRule": "cascade",
"updateRule": "cascade"
}
}
}
]
}

View File

@@ -0,0 +1,39 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20240307132720 extends Migration {
async up(): Promise<void> {
this.addSql('create table if not exists "inventory_item" ("id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, "sku" text null, "origin_country" text null, "hs_code" text null, "mid_code" text null, "material" text null, "weight" int null, "length" int null, "height" int null, "width" int null, "requires_shipping" boolean not null default true, "description" text null, "title" text null, "thumbnail" text null, "metadata" jsonb null, constraint "inventory_item_pkey" primary key ("id"));');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_inventory_item_deleted_at" ON "inventory_item" (deleted_at) WHERE deleted_at IS NOT NULL;');
this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_inventory_item_sku_unique" ON "inventory_item" (sku);');
this.addSql('create table if not exists "inventory_level" ("id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, "inventory_item_id" text not null, "location_id" text not null, "stocked_quantity" int not null default 0, "reserved_quantity" int not null default 0, "incoming_quantity" int not null default 0, "metadata" jsonb null, constraint "inventory_level_pkey" primary key ("id"));');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_inventory_level_deleted_at" ON "inventory_level" (deleted_at) WHERE deleted_at IS NOT NULL;');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_inventory_level_inventory_item_id" ON "inventory_level" (inventory_item_id);');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_inventory_level_location_id" ON "inventory_level" (location_id);');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_inventory_level_location_id" ON "inventory_level" (location_id);');
this.addSql('create table if not exists "reservation_item" ("id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, "line_item_id" text null, "location_id" text not null, "quantity" integer not null, "external_id" text null, "description" text null, "created_by" text null, "metadata" jsonb null, "inventory_item_id" text not null, constraint "reservation_item_pkey" primary key ("id"));');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_reservation_item_deleted_at" ON "reservation_item" (deleted_at) WHERE deleted_at IS NOT NULL;');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_reservation_item_line_item_id" ON "reservation_item" (line_item_id);');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_reservation_item_location_id" ON "reservation_item" (location_id);');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_reservation_item_inventory_item_id" ON "reservation_item" (inventory_item_id);');
this.addSql('alter table if exists "inventory_level" add constraint "inventory_level_inventory_item_id_foreign" foreign key ("inventory_item_id") references "inventory_item" ("id") on update cascade on delete cascade;');
this.addSql('alter table if exists "reservation_item" add constraint "reservation_item_inventory_item_id_foreign" foreign key ("inventory_item_id") references "inventory_item" ("id") on update cascade on delete cascade;');
}
async down(): Promise<void> {
this.addSql('alter table if exists "inventory_level" drop constraint if exists "inventory_level_inventory_item_id_foreign";');
this.addSql('alter table if exists "reservation_item" drop constraint if exists "reservation_item_inventory_item_id_foreign";');
this.addSql('drop table if exists "inventory_item" cascade;');
this.addSql('drop table if exists "inventory_level" cascade;');
this.addSql('drop table if exists "reservation_item" cascade;');
}
}

View File

@@ -0,0 +1,3 @@
export * from "./reservation-item"
export * from "./inventory-item"
export * from "./inventory-level"

View File

@@ -0,0 +1,120 @@
import {
BeforeCreate,
Collection,
Entity,
Filter,
OnInit,
OneToMany,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import {
DALUtils,
createPsqlIndexStatementHelper,
generateEntityId,
} from "@medusajs/utils"
import { DAL } from "@medusajs/types"
import { InventoryLevel } from "./inventory-level"
const InventoryItemDeletedAtIndex = createPsqlIndexStatementHelper({
tableName: "inventory_item",
columns: "deleted_at",
where: "deleted_at IS NOT NULL",
})
const InventoryItemSkuIndex = createPsqlIndexStatementHelper({
tableName: "inventory_item",
columns: "sku",
unique: true,
})
type InventoryItemOptionalProps = DAL.SoftDeletableEntityDateColumns
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export class InventoryItem {
[OptionalProps]: InventoryItemOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@InventoryItemDeletedAtIndex.MikroORMIndex()
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null
@InventoryItemSkuIndex.MikroORMIndex()
@Property({ columnType: "text", nullable: true })
sku: string | null = null
@Property({ columnType: "text", nullable: true })
origin_country: string | null = null
@Property({ columnType: "text", nullable: true })
hs_code: string | null = null
@Property({ columnType: "text", nullable: true })
mid_code: string | null = null
@Property({ columnType: "text", nullable: true })
material: string | null = null
@Property({ type: "int", nullable: true })
weight: number | null = null
@Property({ type: "int", nullable: true })
length: number | null = null
@Property({ type: "int", nullable: true })
height: number | null = null
@Property({ type: "int", nullable: true })
width: number | null = null
@Property({ columnType: "boolean" })
requires_shipping: boolean = true
@Property({ columnType: "text", nullable: true })
description: string | null = null
@Property({ columnType: "text", nullable: true })
title: string | null = null
@Property({ columnType: "text", nullable: true })
thumbnail: string | null = null
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@OneToMany(
() => InventoryLevel,
(inventoryLevel) => inventoryLevel.inventory_item
)
inventory_levels = new Collection<InventoryLevel>(this)
@BeforeCreate()
private beforeCreate(): void {
this.id = generateEntityId(this.id, "iitem")
}
@OnInit()
private onInit(): void {
this.id = generateEntityId(this.id, "iitem")
}
}

View File

@@ -0,0 +1,104 @@
import {
BeforeCreate,
Entity,
Filter,
ManyToOne,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { DALUtils } from "@medusajs/utils"
import { InventoryItem } from "./inventory-item"
import { createPsqlIndexStatementHelper } from "@medusajs/utils"
import { generateEntityId } from "@medusajs/utils"
const InventoryLevelDeletedAtIndex = createPsqlIndexStatementHelper({
tableName: "inventory_level",
columns: "deleted_at",
where: "deleted_at IS NOT NULL",
})
const InventoryLevelInventoryItemIdIndex = createPsqlIndexStatementHelper({
tableName: "inventory_level",
columns: "inventory_item_id",
})
const InventoryLevelLocationIdIndex = createPsqlIndexStatementHelper({
tableName: "inventory_level",
columns: "location_id",
})
const InventoryLevelLocationIdInventoryItemIdIndex =
createPsqlIndexStatementHelper({
tableName: "inventory_level",
columns: "location_id",
})
@Entity()
@InventoryLevelLocationIdInventoryItemIdIndex.MikroORMIndex()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export class InventoryLevel {
@PrimaryKey({ columnType: "text" })
id: string
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@InventoryLevelDeletedAtIndex.MikroORMIndex()
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null
@ManyToOne(() => InventoryItem, {
fieldName: "inventory_item_id",
type: "text",
mapToPk: true,
onDelete: "cascade",
})
@InventoryLevelInventoryItemIdIndex.MikroORMIndex()
inventory_item_id: string
@InventoryLevelLocationIdIndex.MikroORMIndex()
@Property({ type: "text" })
location_id: string
@Property({ type: "int" })
stocked_quantity: number = 0
@Property({ type: "int" })
reserved_quantity: number = 0
@Property({ type: "int" })
incoming_quantity: number = 0
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null
@ManyToOne(() => InventoryItem, {
persist: false,
})
inventory_item: InventoryItem
@BeforeCreate()
private beforeCreate(): void {
this.id = generateEntityId(this.id, "ilev")
this.inventory_item_id ??= this.inventory_item?.id
}
@OnInit()
private onInit(): void {
this.id = generateEntityId(this.id, "ilev")
}
}

View File

@@ -0,0 +1,107 @@
import {
BeforeCreate,
Entity,
Filter,
ManyToOne,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { DALUtils } from "@medusajs/utils"
import { InventoryItem } from "./inventory-item"
import { createPsqlIndexStatementHelper } from "@medusajs/utils"
import { generateEntityId } from "@medusajs/utils"
const ReservationItemDeletedAtIndex = createPsqlIndexStatementHelper({
tableName: "reservation_item",
columns: "deleted_at",
where: "deleted_at IS NOT NULL",
})
const ReservationItemLineItemIdIndex = createPsqlIndexStatementHelper({
tableName: "reservation_item",
columns: "line_item_id",
})
const ReservationItemInventoryItemIdIndex = createPsqlIndexStatementHelper({
tableName: "reservation_item",
columns: "inventory_item_id",
})
const ReservationItemLocationIdIndex = createPsqlIndexStatementHelper({
tableName: "reservation_item",
columns: "location_id",
})
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export class ReservationItem {
@PrimaryKey({ columnType: "text" })
id: string
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@ReservationItemDeletedAtIndex.MikroORMIndex()
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null
@ReservationItemLineItemIdIndex.MikroORMIndex()
@Property({ type: "text", nullable: true })
line_item_id: string | null = null
@ReservationItemLocationIdIndex.MikroORMIndex()
@Property({ type: "text" })
location_id: string
@Property({ columnType: "integer" })
quantity: number
@Property({ type: "text", nullable: true })
external_id: string | null = null
@Property({ type: "text", nullable: true })
description: string | null = null
@Property({ type: "text", nullable: true })
created_by: string | null = null
@Property({ type: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@ReservationItemInventoryItemIdIndex.MikroORMIndex()
@ManyToOne(() => InventoryItem, {
fieldName: "inventory_item_id",
type: "text",
mapToPk: true,
onDelete: "cascade",
})
inventory_item_id: string
@ManyToOne(() => InventoryItem, {
persist: false,
})
inventory_item: InventoryItem
@BeforeCreate()
private beforeCreate(): void {
this.id = generateEntityId(this.id, "ilev")
}
@OnInit()
private onInit(): void {
this.id = generateEntityId(this.id, "ilev")
}
}

View File

@@ -0,0 +1,44 @@
import * as InventoryModels from "@models"
import * as InventoryRepositories from "@repositories"
import * as InventoryServices from "@services"
import InventoryService from "./services/inventory"
import { ModuleExports } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk"
import { ModulesSdkUtils } from "@medusajs/utils"
const migrationScriptOptions = {
moduleName: Modules.INVENTORY,
models: InventoryModels,
pathToMigrations: __dirname + "/migrations",
}
const runMigrations = ModulesSdkUtils.buildMigrationScript(
migrationScriptOptions
)
const revertMigration = ModulesSdkUtils.buildRevertMigrationScript(
migrationScriptOptions
)
const containerLoader = ModulesSdkUtils.moduleContainerLoaderFactory({
moduleModels: InventoryModels,
moduleRepositories: InventoryRepositories,
moduleServices: InventoryServices,
})
const connectionLoader = ModulesSdkUtils.mikroOrmConnectionLoaderFactory({
moduleName: Modules.INVENTORY,
moduleModels: Object.values(InventoryModels),
migrationsPath: __dirname + "/migrations",
})
const service = InventoryService
const loaders = [containerLoader, connectionLoader]
export const moduleDefinition: ModuleExports = {
service,
loaders,
revertMigration,
runMigrations,
}

View File

@@ -0,0 +1,2 @@
export * from "./inventory-level"
export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils"

View File

@@ -0,0 +1,72 @@
import { Context } from "@medusajs/types"
import { InventoryLevel } from "@models"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { mikroOrmBaseRepositoryFactory } from "@medusajs/utils"
export class InventoryLevelRepository extends mikroOrmBaseRepositoryFactory(
InventoryLevel
) {
async getReservedQuantity(
inventoryItemId: string,
locationIds: string[],
context: Context = {}
): Promise<number> {
const manager = super.getActiveManager<SqlEntityManager>(context)
const [result] = (await manager
.getKnex()({ il: "inventory_level" })
.sum("reserved_quantity")
.whereIn("location_id", locationIds)
.andWhere("inventory_item_id", inventoryItemId)) as {
sum: string
}[]
return parseInt(result.sum)
}
async getAvailableQuantity(
inventoryItemId: string,
locationIds: string[],
context: Context = {}
): Promise<number> {
const knex = super.getActiveManager<SqlEntityManager>(context).getKnex()
const [result] = (await knex({
il: "inventory_level",
})
.sum({
stocked_quantity: "stocked_quantity",
reserved_quantity: "reserved_quantity",
})
.whereIn("location_id", locationIds)
.andWhere("inventory_item_id", inventoryItemId)) as {
reserved_quantity: string
stocked_quantity: string
}[]
return (
parseInt(result.stocked_quantity) - parseInt(result.reserved_quantity)
)
}
async getStockedQuantity(
inventoryItemId: string,
locationIds: string[],
context: Context = {}
): Promise<number> {
const knex = super.getActiveManager<SqlEntityManager>(context).getKnex()
const [result] = (await knex({
il: "inventory_level",
})
.sum({
stocked_quantity: "stocked_quantity",
})
.whereIn("location_id", locationIds)
.andWhere("inventory_item_id", inventoryItemId)) as {
stocked_quantity: string
}[]
return parseInt(result.stocked_quantity)
}
}

View File

@@ -0,0 +1,55 @@
export default `
scalar DateTime
scalar JSON
type InventoryItem {
id: ID!
created_at: DateTime!
updated_at: DateTime!
deleted_at: DateTime
sku: String
origin_country: String
hs_code: String
mid_code: String
material: String
weight: Int
length: Int
height: Int
width: Int
requires_shipping: Boolean!
description: String
title: String
thumbnail: String
metadata: JSON
inventory_levels: [InventoryLevel]
}
type InventoryLevel {
id: ID!
created_at: DateTime!
updated_at: DateTime!
deleted_at: DateTime
inventory_item_id: String!
location_id: String!
stocked_quantity: Int!
reserved_quantity: Int!
incoming_quantity: Int!
metadata: JSON
}
type ReservationItem {
id: ID!
created_at: DateTime!
updated_at: DateTime!
deleted_at: DateTime
line_item_id: String
inventory_item_id: String!
location_id: String!
quantity: Int!
external_id: String
description: String
created_by: String
metadata: JSON
}
`

View File

@@ -0,0 +1,5 @@
describe("noop", function () {
it("should run", function () {
expect(true).toBe(true)
})
})

View File

@@ -0,0 +1,2 @@
export { default as InventoryModuleService } from "./inventory"
export { default as InventoryLevelService } from "./inventory-level"

View File

@@ -0,0 +1,79 @@
import {
Context,
CreateInventoryLevelInput,
DAL,
SharedContext,
} from "@medusajs/types"
import {
InjectTransactionManager,
MedusaContext,
ModulesSdkUtils,
} from "@medusajs/utils"
import { InventoryLevel } from "../models/inventory-level"
import { InventoryLevelRepository } from "@repositories"
type InjectedDependencies = {
inventoryLevelRepository: InventoryLevelRepository
}
export default class InventoryLevelService<
TEntity extends InventoryLevel = InventoryLevel
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
InventoryLevel
)<TEntity> {
protected readonly inventoryLevelRepository: InventoryLevelRepository
constructor(container: InjectedDependencies) {
super(container)
this.inventoryLevelRepository = container.inventoryLevelRepository
}
async retrieveStockedQuantity(
inventoryItemId: string,
locationIds: string[] | string,
context: Context = {}
): Promise<number> {
const locationIdArray = Array.isArray(locationIds)
? locationIds
: [locationIds]
return await this.inventoryLevelRepository.getStockedQuantity(
inventoryItemId,
locationIdArray,
context
)
}
async getAvailableQuantity(
inventoryItemId: string,
locationIds: string[] | string,
context: Context = {}
): Promise<number> {
const locationIdArray = Array.isArray(locationIds)
? locationIds
: [locationIds]
return await this.inventoryLevelRepository.getAvailableQuantity(
inventoryItemId,
locationIdArray,
context
)
}
async getReservedQuantity(
inventoryItemId: string,
locationIds: string[] | string,
context: Context = {}
) {
if (!Array.isArray(locationIds)) {
locationIds = [locationIds]
}
return await this.inventoryLevelRepository.getReservedQuantity(
inventoryItemId,
locationIds,
context
)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
{
"compilerOptions": {
"lib": ["es2020"],
"target": "es2020",
"outDir": "./dist",
"esModuleInterop": true,
"declaration": true,
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": false,
"noImplicitReturns": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"allowJs": true,
"skipLibCheck": true,
"downlevelIteration": true, // to use ES5 specific tooling
"baseUrl": ".",
"resolveJsonModule": true,
"paths": {
"@models": ["./src/models"],
"@services": ["./src/services"],
"@repositories": ["./src/repositories"],
"@types": ["./src/types"],
"@utils": ["./src/utils"]
}
},
"include": ["src"],
"exclude": [
"dist",
"./src/**/__tests__",
"./src/**/__mocks__",
"./src/**/__fixtures__",
"node_modules"
]
}

View File

@@ -0,0 +1,5 @@
{
"extends": "./tsconfig.json",
"include": ["src"],
"exclude": ["node_modules"]
}

View File

@@ -22,8 +22,8 @@ export function moduleIntegrationTestRunner({
joinerConfig = [],
schema = "public",
debug = false,
resolve,
testSuite,
resolve,
injectedDependencies = {},
}: {
moduleName: string
@@ -32,8 +32,8 @@ export function moduleIntegrationTestRunner({
joinerConfig?: any[]
schema?: string
dbName?: string
resolve?: string
injectedDependencies?: Record<string, any>
resolve?: string
debug?: boolean
testSuite: <TService = unknown>(options: SuiteOptions<TService>) => () => void
}) {

View File

@@ -0,0 +1,2 @@
export * from "./common/index"
export * from "./mutations"

View File

@@ -204,7 +204,7 @@ export type InventoryLevelDTO = {
/**
* @interface
*
*
* The filters to apply on retrieved reservation items.
*/
export type FilterableReservationItemProps = {
@@ -214,7 +214,7 @@ export type FilterableReservationItemProps = {
id?: string | string[]
/**
* @ignore
*
*
* @privateRemark
* This property is not used.
*/
@@ -247,7 +247,7 @@ export type FilterableReservationItemProps = {
/**
* @interface
*
*
* The filters to apply on retrieved inventory items.
*/
export type FilterableInventoryItemProps = {
@@ -281,12 +281,16 @@ export type FilterableInventoryItemProps = {
requires_shipping?: boolean
}
export interface UpdateInventoryItemInput
extends Partial<CreateInventoryItemInput> {
id: string
}
/**
* @interface
*
*
* The details of the inventory item to be created.
*/
export type CreateInventoryItemInput = {
export interface CreateInventoryItemInput {
/**
* The SKU of the inventory item.
*/
@@ -347,7 +351,7 @@ export type CreateInventoryItemInput = {
/**
* @interface
*
*
* The details of the reservation item to be created.
*/
export type CreateReservationItemInput = {
@@ -387,7 +391,7 @@ export type CreateReservationItemInput = {
/**
* @interface
*
*
* The filters to apply on retrieved inventory levels.
*/
export type FilterableInventoryLevelProps = {
@@ -415,7 +419,7 @@ export type FilterableInventoryLevelProps = {
/**
* @interface
*
*
* The details of the inventory level to be created.
*/
export type CreateInventoryLevelInput = {
@@ -443,7 +447,7 @@ export type CreateInventoryLevelInput = {
/**
* @interface
*
*
* The attributes to update in an inventory level.
*/
export type UpdateInventoryLevelInput = {
@@ -459,7 +463,7 @@ export type UpdateInventoryLevelInput = {
/**
* @interface
*
*
* The attributes to update in an inventory level. The inventory level is identified by the IDs of its associated inventory item and location.
*/
export type BulkUpdateInventoryLevelInput = {
@@ -475,7 +479,7 @@ export type BulkUpdateInventoryLevelInput = {
/**
* @interface
*
*
* The attributes to update in a reservation item.
*/
export type UpdateReservationItemInput = {

View File

@@ -0,0 +1,3 @@
export * from "./inventory-item"
export * from "./inventory-level"
export * from "./reservation-item"

View File

@@ -0,0 +1,124 @@
import { StringComparisonOperator } from "../../common"
/**
* @schema InventoryItemDTO
* type: object
* required:
* - sku
* properties:
* id:
* description: The inventory item's ID.
* type: string
* example: "iitem_12334"
* sku:
* description: The Stock Keeping Unit (SKU) code of the Inventory Item.
* type: string
* hs_code:
* description: The Harmonized System code of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers.
* type: string
* origin_country:
* description: The country in which the Inventory Item was produced. May be used by Fulfillment Providers to pass customs information to shipping carriers.
* type: string
* mid_code:
* description: The Manufacturers Identification code that identifies the manufacturer of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers.
* type: string
* title:
* description: "Title of the inventory item"
* type: string
* description:
* description: "Description of the inventory item"
* type: string
* thumbnail:
* description: "Thumbnail for the inventory item"
* type: string
* material:
* description: The material and composition that the Inventory Item is made of, May be used by Fulfillment Providers to pass customs information to shipping carriers.
* type: string
* weight:
* description: The weight of the Inventory Item. May be used in shipping rate calculations.
* type: number
* height:
* description: The height of the Inventory Item. May be used in shipping rate calculations.
* type: number
* width:
* description: The width of the Inventory Item. May be used in shipping rate calculations.
* type: number
* length:
* description: The length of the Inventory Item. May be used in shipping rate calculations.
* type: number
* requires_shipping:
* description: Whether the item requires shipping.
* type: boolean
* metadata:
* type: object
* description: An optional key-value map with additional details
* example: {car: "white"}
* created_at:
* type: string
* description: "The date with timezone at which the resource was created."
* format: date-time
* updated_at:
* type: string
* description: "The date with timezone at which the resource was updated."
* format: date-time
* deleted_at:
* type: string
* description: "The date with timezone at which the resource was deleted."
* format: date-time
*/
export interface InventoryItemDTO {
id: string
sku?: string | null
origin_country?: string | null
hs_code?: string | null
requires_shipping: boolean
mid_code?: string | null
material?: string | null
weight?: number | null
length?: number | null
height?: number | null
width?: number | null
title?: string | null
description?: string | null
thumbnail?: string | null
metadata?: Record<string, unknown> | null
created_at: string | Date
updated_at: string | Date
deleted_at: string | Date | null
}
/**
* @interface
*
* The filters to apply on retrieved inventory items.
*/
export interface FilterableInventoryItemProps {
/**
* The IDs to filter inventory items by.
*/
id?: string | string[]
/**
* Filter inventory items by the ID of their associated location.
*/
location_id?: string | string[]
/**
* Search term to search inventory items' attributes.
*/
q?: string
/**
* The SKUs to filter inventory items by.
*/
sku?: string | string[] | StringComparisonOperator
/**
* The origin country to filter inventory items by.
*/
origin_country?: string | string[]
/**
* The HS Codes to filter inventory items by.
*/
hs_code?: string | string[] | StringComparisonOperator
/**
* Filter inventory items by whether they require shipping.
*/
requires_shipping?: boolean
}

View File

@@ -0,0 +1,76 @@
import { NumericalComparisonOperator } from "../../common"
/**
* @schema InventoryLevelDTO
* type: object
* required:
* - inventory_item_id
* - location_id
* - stocked_quantity
* - reserved_quantity
* - incoming_quantity
* properties:
* location_id:
* description: the item location ID
* type: string
* stocked_quantity:
* description: the total stock quantity of an inventory item at the given location ID
* type: number
* reserved_quantity:
* description: the reserved 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
* metadata:
* type: object
* description: An optional key-value map with additional details
* example: {car: "white"}
* created_at:
* type: string
* description: "The date with timezone at which the resource was created."
* format: date-time
* updated_at:
* type: string
* description: "The date with timezone at which the resource was updated."
* format: date-time
* deleted_at:
* type: string
* description: "The date with timezone at which the resource was deleted."
* format: date-time
*/
export interface InventoryLevelDTO {
id: string
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
updated_at: string | Date
deleted_at: string | Date | null
}
export interface FilterableInventoryLevelProps {
/**
* Filter inventory levels by the ID of their associated inventory item.
*/
inventory_item_id?: string | string[]
/**
* Filter inventory levels by the ID of their associated inventory location.
*/
location_id?: string | string[]
/**
* Filters to apply on inventory levels' `stocked_quantity` attribute.
*/
stocked_quantity?: number | NumericalComparisonOperator
/**
* Filters to apply on inventory levels' `reserved_quantity` attribute.
*/
reserved_quantity?: number | NumericalComparisonOperator
/**
* Filters to apply on inventory levels' `incoming_quantity` attribute.
*/
incoming_quantity?: number | NumericalComparisonOperator
}

View File

@@ -0,0 +1,107 @@
import {
NumericalComparisonOperator,
StringComparisonOperator,
} from "../../common"
/**
* @schema ReservationItemDTO
* title: "Reservation item"
* description: "Represents a reservation of an inventory item at a stock location"
* type: object
* required:
* - id
* - location_id
* - inventory_item_id
* - quantity
* properties:
* id:
* description: "The id of the reservation item"
* type: string
* location_id:
* description: "The id of the location of the reservation"
* type: string
* inventory_item_id:
* description: "The id of the inventory item the reservation relates to"
* type: string
* description:
* description: "Description of the reservation item"
* type: string
* created_by:
* description: "UserId of user who created the reservation item"
* type: string
* quantity:
* description: "The id of the reservation item"
* type: number
* metadata:
* type: object
* description: An optional key-value map with additional details
* example: {car: "white"}
* created_at:
* type: string
* description: "The date with timezone at which the resource was created."
* format: date-time
* updated_at:
* type: string
* description: "The date with timezone at which the resource was updated."
* format: date-time
* deleted_at:
* type: string
* description: "The date with timezone at which the resource was deleted."
* format: date-time
*/
export interface ReservationItemDTO {
id: string
location_id: string
inventory_item_id: string
quantity: number
line_item_id?: string | null
description?: string | null
created_by?: string | null
metadata: Record<string, unknown> | null
created_at: string | Date
updated_at: string | Date
deleted_at: string | Date | null
}
/**
* @interface
*
* The filters to apply on retrieved reservation items.
*/
export interface FilterableReservationItemProps {
/**
* The IDs to filter reservation items by.
*/
id?: string | string[]
/**
* @ignore
*
* @privateRemark
* This property is not used.
*/
type?: string | string[]
/**
* Filter reservation items by the ID of their associated line item.
*/
line_item_id?: string | string[]
/**
* Filter reservation items by the ID of their associated inventory item.
*/
inventory_item_id?: string | string[]
/**
* Filter reservation items by the ID of their associated location.
*/
location_id?: string | string[]
/**
* Description filters to apply on the reservation items' `description` attribute.
*/
description?: string | StringComparisonOperator
/**
* The "created by" values to filter reservation items by.
*/
created_by?: string | string[]
/**
* Filters to apply on the reservation items' `quantity` attribute.
*/
quantity?: number | NumericalComparisonOperator
}

View File

@@ -1,2 +1,4 @@
export * as InventoryNext from "./bundle"
export * from "./common"
export * from "./service"
export * from "./service-next"

View File

@@ -0,0 +1,3 @@
export * from "./inventory-item"
export * from "./inventory-level"
export * from "./reservation-item"

View File

@@ -0,0 +1,67 @@
export interface UpdateInventoryItemInput
extends Partial<CreateInventoryItemInput> {
id: string
}
/**
* @interface
*
* The details of the inventory item to be created.
*/
export interface CreateInventoryItemInput {
/**
* The SKU of the inventory item.
*/
sku?: string | null
/**
* The origin country of the inventory item.
*/
origin_country?: string | null
/**
* The MID code of the inventory item.
*/
mid_code?: string | null
/**
* The material of the inventory item.
*/
material?: string | null
/**
* The weight of the inventory item.
*/
weight?: number | null
/**
* The length of the inventory item.
*/
length?: number | null
/**
* The height of the inventory item.
*/
height?: number | null
/**
* The width of the inventory item.
*/
width?: number | null
/**
* The title of the inventory item.
*/
title?: string | null
/**
* The description of the inventory item.
*/
description?: string | null
/**
* The thumbnail of the inventory item.
*/
thumbnail?: string | null
/**
* Holds custom data in key-value pairs.
*/
metadata?: Record<string, unknown> | null
/**
* The HS code of the inventory item.
*/
hs_code?: string | null
/**
* Whether the inventory item requires shipping.
*/
requires_shipping?: boolean
}

View File

@@ -0,0 +1,58 @@
export interface CreateInventoryLevelInput {
/**
* The ID of the associated inventory item.
*/
inventory_item_id: string
/**
* The ID of the associated location.
*/
location_id: string
/**
* The stocked quantity of the associated inventory item in the associated location.
*/
stocked_quantity: number
/**
* The reserved quantity of the associated inventory item in the associated location.
*/
reserved_quantity?: number
/**
* The incoming quantity of the associated inventory item in the associated location.
*/
incoming_quantity?: number
}
/**
* @interface
*
* The attributes to update in an inventory level.
*/
export interface UpdateInventoryLevelInput {
/**
* id of the inventory level to update
*/
id: string
/**
* The stocked quantity of the associated inventory item in the associated location.
*/
stocked_quantity?: number
/**
* The incoming quantity of the associated inventory item in the associated location.
*/
incoming_quantity?: number
}
/**
* @interface
*
* The attributes to update in an inventory level. The inventory level is identified by the IDs of its associated inventory item and location.
*/
export type BulkUpdateInventoryLevelInput = {
/**
* The ID of the associated inventory level.
*/
inventory_item_id: string
/**
* The ID of the associated location.
*/
location_id: string
} & UpdateInventoryLevelInput

View File

@@ -0,0 +1,70 @@
/**
* @interface
*
* The attributes to update in a reservation item.
*/
export interface UpdateReservationItemInput {
id: string
/**
* The reserved quantity.
*/
quantity?: number
/**
* The ID of the associated location.
*/
location_id?: string
/**
* The description of the reservation item.
*/
description?: string
/**
* Holds custom data in key-value pairs.
*/
metadata?: Record<string, unknown> | null
}
/**
* @interface
*
* The details of the reservation item to be created.
*/
export interface CreateReservationItemInput {
/**
* The ID of the associated line item.
*/
line_item_id?: string
/**
* The ID of the associated inventory item.
*/
inventory_item_id: string
/**
* The ID of the associated location.
*/
location_id: string
/**
* The reserved quantity.
*/
quantity: number
/**
* The description of the reservation.
*/
description?: string
/**
* The user or system that created the reservation. Can be any form of identification string.
*/
created_by?: string
/**
* An ID associated with an external third-party system that the reservation item is connected to.
*/
external_id?: string
/**
* Holds custom data in key-value pairs.
*/
metadata?: Record<string, unknown> | null
}
export interface ReserveQuantityContext {
locationId?: string
lineItemId?: string
salesChannelId?: string | null
}

View File

@@ -0,0 +1,963 @@
import { RestoreReturn, SoftDeleteReturn } from "../dal"
import { Context } from "../shared-context"
import { FindConfig } from "../common"
import { IModuleService } from "../modules-sdk"
import { InventoryNext } from "."
/**
* The main service interface for the inventory module.
*/
export interface IInventoryServiceNext extends IModuleService {
/**
* This method is used to retrieve a paginated list of inventory items along with the total count of available inventory items satisfying the provided filters.
* @param {FilterableInventoryItemProps} selector - The filters to apply on the retrieved inventory items.
* @param {FindConfig<InventoryItemDTO>} config -
* The configurations determining how the inventory items are retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a inventory item.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @return {Promise<[InventoryItemDTO[], number]>} The list of inventory items along with the total count.
*
* @example
* To retrieve a list of inventory items using their IDs:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveInventoryItems (ids: string[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const [inventoryItems, count] = await inventoryModule.listInventoryItems({
* id: ids
* })
*
* // do something with the inventory items or return them
* }
* ```
*
* To specify relations that should be retrieved within the inventory items:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveInventoryItems (ids: string[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const [inventoryItems, count] = await inventoryModule.listInventoryItems({
* id: ids
* }, {
* relations: ["inventory_level"]
* })
*
* // do something with the inventory items or return them
* }
* ```
*
* By default, only the first `10` records are retrieved. You can control pagination by specifying the `skip` and `take` properties of the `config` parameter:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveInventoryItems (ids: string[], skip: number, take: number) {
* const inventoryModule = await initializeInventoryModule({})
*
* const [inventoryItems, count] = await inventoryModule.listInventoryItems({
* id: ids
* }, {
* relations: ["inventory_level"],
* skip,
* take
* })
*
* // do something with the inventory items or return them
* }
* ```
*/
list(
selector: InventoryNext.FilterableInventoryItemProps,
config?: FindConfig<InventoryNext.InventoryItemDTO>,
context?: Context
): Promise<InventoryNext.InventoryItemDTO[]>
listAndCount(
selector: InventoryNext.FilterableInventoryItemProps,
config?: FindConfig<InventoryNext.InventoryItemDTO>,
context?: Context
): Promise<[InventoryNext.InventoryItemDTO[], number]>
/**
* This method is used to retrieve a paginated list of reservation items along with the total count of available reservation items satisfying the provided filters.
* @param {FilterableReservationItemProps} selector - The filters to apply on the retrieved reservation items.
* @param {FindConfig<ReservationItemDTO>} config -
* The configurations determining how the reservation items are retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a reservation item.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @return {Promise<[ReservationItemDTO[], number]>} The list of reservation items along with the total count.
*
* @example
* To retrieve a list of reservation items using their IDs:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveReservationItems (ids: string[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const [reservationItems, count] = await inventoryModule.listReservationItems({
* id: ids
* })
*
* // do something with the reservation items or return them
* }
* ```
*
* To specify relations that should be retrieved within the reservation items:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveReservationItems (ids: string[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const [reservationItems, count] = await inventoryModule.listReservationItems({
* id: ids
* }, {
* relations: ["inventory_item"]
* })
*
* // do something with the reservation items or return them
* }
* ```
*
* By default, only the first `10` records are retrieved. You can control pagination by specifying the `skip` and `take` properties of the `config` parameter:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveReservationItems (ids: string[], skip: number, take: number) {
* const inventoryModule = await initializeInventoryModule({})
*
* const [reservationItems, count] = await inventoryModule.listReservationItems({
* id: ids
* }, {
* relations: ["inventory_item"],
* skip,
* take
* })
*
* // do something with the reservation items or return them
* }
* ```
*/
listReservationItems(
selector: InventoryNext.FilterableReservationItemProps,
config?: FindConfig<InventoryNext.ReservationItemDTO>,
context?: Context
): Promise<InventoryNext.ReservationItemDTO[]>
listAndCountReservationItems(
selector: InventoryNext.FilterableReservationItemProps,
config?: FindConfig<InventoryNext.ReservationItemDTO>,
context?: Context
): Promise<[InventoryNext.ReservationItemDTO[], number]>
/**
* This method is used to retrieve a paginated list of inventory levels along with the total count of available inventory levels satisfying the provided filters.
* @param {FilterableInventoryLevelProps} selector - The filters to apply on the retrieved inventory levels.
* @param {FindConfig<InventoryLevelDTO>} config -
* The configurations determining how the inventory levels are retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a inventory level.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @return {Promise<[InventoryLevelDTO[], number]>} The list of inventory levels along with the total count.
*
* @example
* To retrieve a list of inventory levels using their IDs:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveInventoryLevels (inventoryItemIds: string[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const [inventoryLevels, count] = await inventoryModule.listInventoryLevels({
* inventory_item_id: inventoryItemIds
* })
*
* // do something with the inventory levels or return them
* }
* ```
*
* To specify relations that should be retrieved within the inventory levels:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveInventoryLevels (inventoryItemIds: string[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const [inventoryLevels, count] = await inventoryModule.listInventoryLevels({
* inventory_item_id: inventoryItemIds
* }, {
* relations: ["inventory_item"]
* })
*
* // do something with the inventory levels or return them
* }
* ```
*
* By default, only the first `10` records are retrieved. You can control pagination by specifying the `skip` and `take` properties of the `config` parameter:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveInventoryLevels (inventoryItemIds: string[], skip: number, take: number) {
* const inventoryModule = await initializeInventoryModule({})
*
* const [inventoryLevels, count] = await inventoryModule.listInventoryLevels({
* inventory_item_id: inventoryItemIds
* }, {
* relations: ["inventory_item"],
* skip,
* take
* })
*
* // do something with the inventory levels or return them
* }
* ```
*/
listInventoryLevels(
selector: InventoryNext.FilterableInventoryLevelProps,
config?: FindConfig<InventoryNext.InventoryLevelDTO>,
context?: Context
): Promise<InventoryNext.InventoryLevelDTO[]>
listAndCountInventoryLevels(
selector: InventoryNext.FilterableInventoryLevelProps,
config?: FindConfig<InventoryNext.InventoryLevelDTO>,
context?: Context
): Promise<[InventoryNext.InventoryLevelDTO[], number]>
/**
* This method is used to retrieve an inventory item by its ID
*
* @param {string} inventoryItemId - The ID of the inventory item to retrieve.
* @param {FindConfig<InventoryItemDTO>} config -
* The configurations determining how the inventory item is retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a inventory item.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<InventoryItemDTO>} The retrieved inventory item.
*
* @example
* A simple example that retrieves a inventory item by its ID:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveInventoryItem (id: string) {
* const inventoryModule = await initializeInventoryModule({})
*
* const inventoryItem = await inventoryModule.retrieveInventoryItem(id)
*
* // do something with the inventory item or return it
* }
* ```
*
* To specify relations that should be retrieved:
*
* ```ts
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveInventoryItem (id: string) {
* const inventoryModule = await initializeInventoryModule({})
*
* const inventoryItem = await inventoryModule.retrieveInventoryItem(id, {
* relations: ["inventory_level"]
* })
*
* // do something with the inventory item or return it
* }
* ```
*/
retrieve(
inventoryItemId: string,
config?: FindConfig<InventoryNext.InventoryItemDTO>,
context?: Context
): Promise<InventoryNext.InventoryItemDTO>
/**
* This method is used to retrieve an inventory level for an inventory item and a location.
*
* @param {string} inventoryItemId - The ID of the inventory item.
* @param {string} locationId - The ID of the location.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<InventoryLevelDTO>} The retrieved inventory level.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveInventoryLevel (
* inventoryItemId: string,
* locationId: string
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* const inventoryLevel = await inventoryModule.retrieveInventoryLevel(
* inventoryItemId,
* locationId
* )
*
* // do something with the inventory level or return it
* }
*/
retrieveInventoryLevelByItemAndLocation(
inventoryItemId: string,
locationId: string,
context?: Context
): Promise<InventoryNext.InventoryLevelDTO>
retrieveInventoryLevel(
inventoryLevelId: string,
config?: FindConfig<InventoryNext.InventoryLevelDTO>,
context?: Context
): Promise<InventoryNext.InventoryLevelDTO>
/**
* This method is used to retrieve a reservation item by its ID.
*
* @param {string} reservationId - The ID of the reservation item.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<ReservationItemDTO>} The retrieved reservation item.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveReservationItem (id: string) {
* const inventoryModule = await initializeInventoryModule({})
*
* const reservationItem = await inventoryModule.retrieveReservationItem(id)
*
* // do something with the reservation item or return it
* }
*/
retrieveReservationItem(
reservationId: string,
config?: FindConfig<InventoryNext.ReservationItemDTO>,
context?: Context
): Promise<InventoryNext.ReservationItemDTO>
/**
* This method is used to create reservation items.
*
* @param {CreateReservationItemInput[]} input - The details of the reservation items to create.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns { Promise<ReservationItemDTO[]>} The created reservation items' details.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function createReservationItems (items: {
* inventory_item_id: string,
* location_id: string,
* quantity: number
* }[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const reservationItems = await inventoryModule.createReservationItems(
* items
* )
*
* // do something with the reservation items or return them
* }
*/
createReservationItems(
input: InventoryNext.CreateReservationItemInput[],
context?: Context
): Promise<InventoryNext.ReservationItemDTO[]>
createReservationItems(
input: InventoryNext.CreateReservationItemInput,
context?: Context
): Promise<InventoryNext.ReservationItemDTO>
/**
* This method is used to create inventory items.
*
* @param {CreateInventoryItemInput[]} input - The details of the inventory items to create.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<InventoryItemDTO[]>} The created inventory items' details.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function createInventoryItems (items: {
* sku: string,
* requires_shipping: boolean
* }[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const inventoryItems = await inventoryModule.createInventoryItems(
* items
* )
*
* // do something with the inventory items or return them
* }
*/
create(
input: InventoryNext.CreateInventoryItemInput[],
context?: Context
): Promise<InventoryNext.InventoryItemDTO[]>
create(
input: InventoryNext.CreateInventoryItemInput,
context?: Context
): Promise<InventoryNext.InventoryItemDTO>
/**
* This method is used to create inventory levels.
*
* @param {CreateInventoryLevelInput[]} data - The details of the inventory levels to create.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<InventoryLevelDTO[]>} The created inventory levels' details.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function createInventoryLevels (items: {
* inventory_item_id: string
* location_id: string
* stocked_quantity: number
* }[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const inventoryLevels = await inventoryModule.createInventoryLevels(
* items
* )
*
* // do something with the inventory levels or return them
* }
*/
createInventoryLevels(
data: InventoryNext.CreateInventoryLevelInput[],
context?: Context
): Promise<InventoryNext.InventoryLevelDTO[]>
createInventoryLevels(
data: InventoryNext.CreateInventoryLevelInput,
context?: Context
): Promise<InventoryNext.InventoryLevelDTO>
/**
* This method is used to update inventory levels. Each inventory level is identified by the IDs of its associated inventory item and location.
*
* @param {BulkUpdateInventoryLevelInput} updates - The attributes to update in each inventory level.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<InventoryLevelDTO[]>} The updated inventory levels' details.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function updateInventoryLevels (items: {
* inventory_item_id: string,
* location_id: string,
* stocked_quantity: number
* }[]) {
* const inventoryModule = await initializeInventoryModule({})
*
* const inventoryLevels = await inventoryModule.updateInventoryLevels(
* items
* )
*
* // do something with the inventory levels or return them
* }
*/
updateInventoryLevels(
updates: InventoryNext.BulkUpdateInventoryLevelInput[],
context?: Context
): Promise<InventoryNext.InventoryLevelDTO[]>
updateInventoryLevels(
updates: InventoryNext.BulkUpdateInventoryLevelInput,
context?: Context
): Promise<InventoryNext.InventoryLevelDTO>
/**
* This method is used to update an inventory item.
*
* @param {string} inventoryItemId - The ID of the inventory item.
* @param {Partial<CreateInventoryItemInput>} input - The attributes to update in the inventory item.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<InventoryItemDTO>} The updated inventory item's details.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function updateInventoryItem (
* inventoryItemId: string,
* sku: string
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* const inventoryItem = await inventoryModule.updateInventoryItem(
* inventoryItemId,
* {
* sku
* }
* )
*
* // do something with the inventory item or return it
* }
*/
update(
input: InventoryNext.UpdateInventoryItemInput,
context?: Context
): Promise<InventoryNext.InventoryItemDTO>
update(
input: InventoryNext.UpdateInventoryItemInput[],
context?: Context
): Promise<InventoryNext.InventoryItemDTO[]>
/**
* This method is used to update a reservation item.
*
* @param {string} reservationItemId - The ID of the reservation item.
* @param {UpdateReservationItemInput} input - The attributes to update in the reservation item.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<ReservationItemDTO>} The updated reservation item.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function updateReservationItem (
* reservationItemId: string,
* quantity: number
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* const reservationItem = await inventoryModule.updateReservationItem(
* reservationItemId,
* {
* quantity
* }
* )
*
* // do something with the reservation item or return it
* }
*/
updateReservationItems(
input: InventoryNext.UpdateReservationItemInput,
context?: Context
): Promise<InventoryNext.ReservationItemDTO>
updateReservationItems(
input: InventoryNext.UpdateReservationItemInput[],
context?: Context
): Promise<InventoryNext.ReservationItemDTO[]>
/**
* This method is used to delete the reservation items associated with a line item or multiple line items.
*
* @param {string | string[]} lineItemId - The ID(s) of the line item(s).
* @param {Context} context - A context used to share re9sources, such as transaction manager, between the application and the module.
* @returns {Promise<void>} Resolves when the reservation items are successfully deleted.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function deleteReservationItemsByLineItem (
* lineItemIds: string[]
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* await inventoryModule.deleteReservationItemsByLineItem(
* lineItemIds
* )
* }
*/
deleteReservationItemsByLineItem(
lineItemId: string | string[],
context?: Context
): Promise<void>
/**
* This method is used to delete a reservation item or multiple reservation items by their IDs.
*
* @param {string | string[]} reservationItemId - The ID(s) of the reservation item(s) to delete.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<void>} Resolves when the reservation item(s) are successfully deleted.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function deleteReservationItems (
* reservationItemIds: string[]
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* await inventoryModule.deleteReservationItem(
* reservationItemIds
* )
* }
*/
deleteReservationItems(
reservationItemId: string | string[],
context?: Context
): Promise<void>
/**
* This method is used to delete an inventory item or multiple inventory items. The inventory items are only soft deleted and can be restored using the
* {@link restoreInventoryItem} method.
*
* @param {string | string[]} inventoryItemId - The ID(s) of the inventory item(s) to delete.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<void>} Resolves when the inventory item(s) are successfully deleted.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function deleteInventoryItem (
* inventoryItems: string[]
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* await inventoryModule.deleteInventoryItem(
* inventoryItems
* )
* }
*/
delete(inventoryItemId: string | string[], context?: Context): Promise<void>
/**
* Soft delete inventory items
* @param inventoryItemIds
* @param config
* @param sharedContext
*/
softDelete<TReturnableLinkableKeys extends string = string>(
inventoryItemIds: string[],
config?: SoftDeleteReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
/**
* This method is used to restore an inventory item or multiple inventory items that were previously deleted using the {@link deleteInventoryItem} method.
*
* @param {string[]} inventoryItemId - The ID(s) of the inventory item(s) to restore.
* @param {RestoreReturn<TReturnableLinkableKeys>} config - Restore config
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<void>} Resolves when the inventory item(s) are successfully restored.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function restoreInventoryItem (
* inventoryItems: string[]
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* await inventoryModule.restoreInventoryItem(
* inventoryItems
* )
* }
*/
restore<TReturnableLinkableKeys extends string = string>(
inventoryItemIds: string[],
config?: RestoreReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
/**
* This method deletes the inventory item level(s) for the ID(s) of associated location(s).
*
* @param {string | string[]} locationId - The ID(s) of the associated location(s).
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<void>} Resolves when the inventory item level(s) are successfully restored.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function deleteInventoryItemLevelByLocationId (
* locationIds: string[]
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* await inventoryModule.deleteInventoryItemLevelByLocationId(
* locationIds
* )
* }
*/
deleteInventoryItemLevelByLocationId(
locationId: string | string[],
context?: Context
): Promise<[object[], Record<string, unknown[]>]>
/**
* This method deletes reservation item(s) by the ID(s) of associated location(s).
*
* @param {string | string[]} locationId - The ID(s) of the associated location(s).
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<void>} Resolves when the reservation item(s) are successfully restored.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function deleteReservationItemByLocationId (
* locationIds: string[]
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* await inventoryModule.deleteReservationItemByLocationId(
* locationIds
* )
* }
*/
deleteReservationItemByLocationId(
locationId: string | string[],
context?: Context
): Promise<void>
/**
* This method is used to delete an inventory level. The inventory level is identified by the IDs of its associated inventory item and location.
*
* @param {string} inventoryItemId - The ID of the associated inventory item.
* @param {string} locationId - The ID of the associated location.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<void>} Resolves when the inventory level(s) are successfully restored.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function deleteInventoryLevel (
* inventoryItemId: string,
* locationId: string
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* await inventoryModule.deleteInventoryLevel(
* inventoryItemId,
* locationId
* )
* }
*/
deleteInventoryLevel(
inventoryItemId: string,
locationId: string,
context?: Context
): Promise<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.
*
* @param {string} inventoryItemId - The ID of the associated inventory item.
* @param {string} locationId - The ID of the associated location.
* @param {number} adjustment - A positive or negative number used to adjust the inventory level's stocked quantity.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<InventoryLevelDTO>} The inventory level's details.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function adjustInventory (
* inventoryItemId: string,
* locationId: string,
* adjustment: number
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* const inventoryLevel = await inventoryModule.adjustInventory(
* inventoryItemId,
* locationId,
* adjustment
* )
*
* // do something with the inventory level or return it.
* }
*/
adjustInventory(
inventoryItemId: string,
locationId: string,
adjustment: number,
context?: Context
): Promise<InventoryNext.InventoryLevelDTO>
/**
* This method is used to confirm whether the specified quantity of an inventory item is available in the specified locations.
*
* @param {string} inventoryItemId - The ID of the inventory item to check its availability.
* @param {string[]} locationIds - The IDs of the locations to check the quantity availability in.
* @param {number} quantity - The quantity to check if available for the inventory item in the specified locations.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<boolean>} Whether the specified quantity is available for the inventory item in the specified locations.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function confirmInventory (
* inventoryItemId: string,
* locationIds: string[],
* quantity: number
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* return await inventoryModule.confirmInventory(
* inventoryItemId,
* locationIds,
* quantity
* )
* }
*/
confirmInventory(
inventoryItemId: string,
locationIds: string[],
quantity: number,
context?: Context
): Promise<boolean>
/**
* This method is used to retrieve the available quantity of an inventory item within the specified locations.
*
* @param {string} inventoryItemId - The ID of the inventory item to retrieve its quantity.
* @param {string[]} locationIds - The IDs of the locations to retrieve the available quantity from.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<number>} The available quantity of the inventory item in the specified locations.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveAvailableQuantity (
* inventoryItemId: string,
* locationIds: string[],
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* const quantity = await inventoryModule.retrieveAvailableQuantity(
* inventoryItemId,
* locationIds,
* )
*
* // do something with the quantity or return it
* }
*/
retrieveAvailableQuantity(
inventoryItemId: string,
locationIds: string[],
context?: Context
): Promise<number>
/**
* This method is used to retrieve the stocked quantity of an inventory item within the specified locations.
*
* @param {string} inventoryItemId - The ID of the inventory item to retrieve its stocked quantity.
* @param {string[]} locationIds - The IDs of the locations to retrieve the stocked quantity from.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<number>} The stocked quantity of the inventory item in the specified locations.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveStockedQuantity (
* inventoryItemId: string,
* locationIds: string[],
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* const quantity = await inventoryModule.retrieveStockedQuantity(
* inventoryItemId,
* locationIds,
* )
*
* // do something with the quantity or return it
* }
*/
retrieveStockedQuantity(
inventoryItemId: string,
locationIds: string[],
context?: Context
): Promise<number>
/**
* This method is used to retrieve the reserved quantity of an inventory item within the specified locations.
*
* @param {string} inventoryItemId - The ID of the inventory item to retrieve its reserved quantity.
* @param {string[]} locationIds - The IDs of the locations to retrieve the reserved quantity from.
* @param {Context} context - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<number>} The reserved quantity of the inventory item in the specified locations.
*
* @example
* import {
* initialize as initializeInventoryModule,
* } from "@medusajs/inventory"
*
* async function retrieveReservedQuantity (
* inventoryItemId: string,
* locationIds: string[],
* ) {
* const inventoryModule = await initializeInventoryModule({})
*
* const quantity = await inventoryModule.retrieveReservedQuantity(
* inventoryItemId,
* locationIds,
* )
*
* // do something with the quantity or return it
* }
*/
retrieveReservedQuantity(
inventoryItemId: string,
locationIds: string[],
context?: Context
): Promise<number>
}

View File

@@ -12,4 +12,5 @@ export * as PromotionUtils from "./promotion"
export * as SearchUtils from "./search"
export * as ShippingProfileUtils from "./shipping"
export * as UserUtils from "./user"
export * as InventoryUtils from "./inventory"
export * as ApiKeyUtils from "./api-key"

View File

@@ -0,0 +1,12 @@
import { partitionArray } from "../../../dist"
describe("partitionArray", function () {
it("should split array according to predicate", function () {
const res = partitionArray([1, 2, 3, 4, 5], (x) => x % 2 === 0)
expect(res).toEqual([
[2, 4],
[1, 3, 5],
])
})
})

View File

@@ -32,6 +32,7 @@ export * from "./medusa-container"
export * from "./object-from-string-path"
export * from "./object-to-string-path"
export * from "./optional-numeric-serializer"
export * from "./partition-array"
export * from "./pick-deep"
export * from "./pick-value-from-object"
export * from "./plurailze"

View File

@@ -0,0 +1,30 @@
/**
* Partitions an array into two arrays based on a predicate function
* @example
* const result = partitionArray([1, 2, 3, 4, 5], (x) => x % 2 === 0)
*
* console.log(result)
*
* // output: [[2, 4], [1, 3, 5]]
*
* @param {T} input input array of type T
* @param {(T) => boolean} predicate function to use when split array elements
*/
export const partitionArray = <T>(
input: T[],
predicate: (T) => boolean
): [T[], T[]] => {
return input.reduce(
([pos, neg], currentElement) => {
if (predicate(currentElement)) {
pos.push(currentElement)
} else {
neg.push(currentElement)
}
return [pos, neg]
},
[[], []] as [T[], T[]]
)
}

View File

@@ -2,6 +2,7 @@ export enum CommonEvents {
CREATED = "created",
UPDATED = "updated",
DELETED = "deleted",
RESTORED = "restored",
ATTACHED = "attached",
DETACHED = "detached",
}

View File

@@ -8,6 +8,7 @@ export * from "./event-bus"
export * from "./exceptions"
export * from "./feature-flags"
export * from "./fulfillment"
export * from "./inventory"
export * from "./modules-sdk"
export * from "./orchestration"
export * from "./order"

View File

@@ -0,0 +1,14 @@
import { CommonEvents } from "../event-bus"
export const InventoryEvents = {
created: "inventory-item." + CommonEvents.CREATED,
updated: "inventory-item." + CommonEvents.UPDATED,
deleted: "inventory-item." + CommonEvents.DELETED,
restored: "inventory-item." + CommonEvents.RESTORED,
reservation_item_created: "reservation-item." + CommonEvents.CREATED,
reservation_item_updated: "reservation-item." + CommonEvents.UPDATED,
reservation_item_deleted: "reservation-item." + CommonEvents.DELETED,
inventory_level_deleted: "inventory-level." + CommonEvents.DELETED,
inventory_level_created: "inventory-level." + CommonEvents.CREATED,
inventory_level_updated: "inventory-level." + CommonEvents.UPDATED,
}

View File

@@ -0,0 +1 @@
export * from "./events"

View File

@@ -6,10 +6,11 @@ import {
ModuleServiceInitializeOptions,
RepositoryService,
} from "@medusajs/types"
import { asClass } from "awilix"
import { internalModuleServiceFactory } from "../internal-module-service-factory"
import { lowerCaseFirst } from "../../common"
import { mikroOrmBaseRepositoryFactory } from "../../dal"
import { internalModuleServiceFactory } from "../internal-module-service-factory"
type RepositoryLoaderOptions = {
moduleModels: Record<string, any>

View File

@@ -8311,6 +8311,31 @@ __metadata:
languageName: unknown
linkType: soft
"@medusajs/inventory-next@workspace:packages/inventory-next":
version: 0.0.0-use.local
resolution: "@medusajs/inventory-next@workspace:packages/inventory-next"
dependencies:
"@medusajs/modules-sdk": ^1.12.4
"@medusajs/types": ^1.11.12
"@medusajs/utils": ^1.11.1
"@mikro-orm/cli": 5.9.7
"@mikro-orm/core": 5.9.7
"@mikro-orm/migrations": 5.9.7
"@mikro-orm/postgresql": 5.9.7
awilix: ^8.0.0
cross-env: ^5.2.1
dotenv: 16.4.5
jest: ^29.6.3
knex: 2.4.2
medusa-test-utils: ^1.1.40
rimraf: ^5.0.1
ts-jest: ^29.1.1
ts-node: ^10.9.1
tsc-alias: ^1.8.6
typescript: ^5.1.6
languageName: unknown
linkType: soft
"@medusajs/inventory@workspace:^, @medusajs/inventory@workspace:packages/inventory":
version: 0.0.0-use.local
resolution: "@medusajs/inventory@workspace:packages/inventory"