feat(medusa): Modules initializer (#3352)
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/inventory": patch
|
||||||
|
"medusa-core-utils": patch
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(medusa): Modules initializer
|
||||||
|
|
||||||
|
### Loading modules in a project
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
``` typescript
|
||||||
|
import { InventoryServiceInitializeOptions, initialize } from "@medusajs/inventory"
|
||||||
|
|
||||||
|
const options: InventoryServiceInitializeOptions = {
|
||||||
|
database: {
|
||||||
|
type: "postgres",
|
||||||
|
url: DB_URL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const inventoryService = await initialize(options)
|
||||||
|
const newInventoryItem = await inventoryService.createInventoryItem({
|
||||||
|
sku: "sku_123",
|
||||||
|
})
|
||||||
|
```
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
const path = require("path")
|
const path = require("path")
|
||||||
|
|
||||||
const { createConnection } = require("typeorm")
|
const { DataSource } = require("typeorm")
|
||||||
const { getConfigFile } = require("medusa-core-utils")
|
const { getConfigFile } = require("medusa-core-utils")
|
||||||
|
|
||||||
const DB_HOST = process.env.DB_HOST
|
const DB_HOST = process.env.DB_HOST
|
||||||
@@ -14,14 +14,16 @@ process.env.NODE_ENV = "development"
|
|||||||
require("./dev-require")
|
require("./dev-require")
|
||||||
|
|
||||||
async function createDB() {
|
async function createDB() {
|
||||||
const connection = await createConnection({
|
const connection = new DataSource({
|
||||||
type: "postgres",
|
type: "postgres",
|
||||||
url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}`,
|
url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await connection.initialize()
|
||||||
|
|
||||||
await connection.query(`DROP DATABASE IF EXISTS "${DB_NAME}";`)
|
await connection.query(`DROP DATABASE IF EXISTS "${DB_NAME}";`)
|
||||||
await connection.query(`CREATE DATABASE "${DB_NAME}";`)
|
await connection.query(`CREATE DATABASE "${DB_NAME}";`)
|
||||||
await connection.close()
|
await connection.destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -47,6 +49,7 @@ module.exports = {
|
|||||||
const {
|
const {
|
||||||
getEnabledMigrations,
|
getEnabledMigrations,
|
||||||
getModuleSharedResources,
|
getModuleSharedResources,
|
||||||
|
runIsolatedModulesMigration,
|
||||||
} = require("@medusajs/medusa/dist/commands/utils/get-migrations")
|
} = require("@medusajs/medusa/dist/commands/utils/get-migrations")
|
||||||
|
|
||||||
const entities = modelsLoader({}, { register: false })
|
const entities = modelsLoader({}, { register: false })
|
||||||
@@ -72,7 +75,7 @@ module.exports = {
|
|||||||
|
|
||||||
await createDB()
|
await createDB()
|
||||||
|
|
||||||
const dbConnection = await createConnection({
|
const dbConnection = new DataSource({
|
||||||
type: "postgres",
|
type: "postgres",
|
||||||
url: DB_URL,
|
url: DB_URL,
|
||||||
entities: enabledEntities.concat(moduleModels),
|
entities: enabledEntities.concat(moduleModels),
|
||||||
@@ -80,8 +83,12 @@ module.exports = {
|
|||||||
// logging: true,
|
// logging: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await dbConnection.initialize()
|
||||||
|
|
||||||
await dbConnection.runMigrations()
|
await dbConnection.runMigrations()
|
||||||
|
|
||||||
|
await runIsolatedModulesMigration(configModule)
|
||||||
|
|
||||||
return dbConnection
|
return dbConnection
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,16 @@
|
|||||||
"author": "Medusa",
|
"author": "Medusa",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@medusajs/medusa": "*",
|
"@medusajs/types": "*",
|
||||||
"cross-env": "^5.2.1",
|
"cross-env": "^5.2.1",
|
||||||
"jest": "^25.5.4",
|
"jest": "^25.5.4",
|
||||||
"ts-jest": "^25.5.1",
|
"ts-jest": "^25.5.1",
|
||||||
"typescript": "^4.4.4"
|
"typescript": "^4.4.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@medusajs/medusa": "^1.7.7",
|
||||||
"@medusajs/modules-sdk": "*",
|
"@medusajs/modules-sdk": "*",
|
||||||
|
"@medusajs/utils": "^0.0.1",
|
||||||
"awilix": "^8.0.0",
|
"awilix": "^8.0.0",
|
||||||
"typeorm": "^0.3.11"
|
"typeorm": "^0.3.11"
|
||||||
},
|
},
|
||||||
@@ -36,6 +38,6 @@
|
|||||||
"test:unit": "jest --passWithNoTests"
|
"test:unit": "jest --passWithNoTests"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@medusajs/medusa": "1.7.13"
|
"@medusajs/types": "^0.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import loadConnection from "./loaders/connection"
|
|||||||
import loadContainer from "./loaders/container"
|
import loadContainer from "./loaders/container"
|
||||||
|
|
||||||
import migrations from "./migrations"
|
import migrations from "./migrations"
|
||||||
|
import { revertMigration, runMigrations } from "./migrations/run-migration"
|
||||||
import * as InventoryModels from "./models"
|
import * as InventoryModels from "./models"
|
||||||
import InventoryService from "./services/inventory"
|
import InventoryService from "./services/inventory"
|
||||||
|
|
||||||
@@ -16,6 +17,12 @@ const moduleDefinition: ModuleExports = {
|
|||||||
migrations,
|
migrations,
|
||||||
loaders,
|
loaders,
|
||||||
models,
|
models,
|
||||||
|
runMigrations,
|
||||||
|
revertMigration,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default moduleDefinition
|
export default moduleDefinition
|
||||||
|
|
||||||
|
export * from "./initialize"
|
||||||
|
export * from "./types"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { IEventBusService, IInventoryService } from "@medusajs/medusa"
|
||||||
|
import {
|
||||||
|
ExternalModuleDeclaration,
|
||||||
|
InternalModuleDeclaration,
|
||||||
|
MedusaModule,
|
||||||
|
} from "@medusajs/modules-sdk"
|
||||||
|
import { InventoryServiceInitializeOptions } from "../types"
|
||||||
|
|
||||||
|
export const initialize = async (
|
||||||
|
options?: InventoryServiceInitializeOptions | ExternalModuleDeclaration,
|
||||||
|
injectedDependencies?: {
|
||||||
|
eventBusService: IEventBusService
|
||||||
|
}
|
||||||
|
): Promise<IInventoryService> => {
|
||||||
|
const serviceKey = "inventoryService"
|
||||||
|
const loaded = await MedusaModule.bootstrap(
|
||||||
|
serviceKey,
|
||||||
|
"@medusajs/inventory",
|
||||||
|
options as InternalModuleDeclaration | ExternalModuleDeclaration,
|
||||||
|
injectedDependencies
|
||||||
|
)
|
||||||
|
|
||||||
|
return loaded[serviceKey] as IInventoryService
|
||||||
|
}
|
||||||
@@ -6,9 +6,10 @@ import {
|
|||||||
} from "@medusajs/modules-sdk"
|
} from "@medusajs/modules-sdk"
|
||||||
import { DataSource, DataSourceOptions } from "typeorm"
|
import { DataSource, DataSourceOptions } from "typeorm"
|
||||||
|
|
||||||
import * as InventoryModels from "../models"
|
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
import { asValue } from "awilix"
|
import { asValue } from "awilix"
|
||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
import * as InventoryModels from "../models"
|
||||||
|
import { InventoryServiceInitializeOptions } from "../types"
|
||||||
|
|
||||||
export default async (
|
export default async (
|
||||||
{ options, container }: LoaderOptions,
|
{ options, container }: LoaderOptions,
|
||||||
@@ -21,7 +22,8 @@ export default async (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const dbData = options?.database as Record<string, string>
|
const dbData =
|
||||||
|
options?.database as InventoryServiceInitializeOptions["database"]
|
||||||
|
|
||||||
if (!dbData) {
|
if (!dbData) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -32,13 +34,13 @@ export default async (
|
|||||||
|
|
||||||
const entities = Object.values(InventoryModels)
|
const entities = Object.values(InventoryModels)
|
||||||
const dataSource = new DataSource({
|
const dataSource = new DataSource({
|
||||||
type: dbData.database_type,
|
type: dbData.type,
|
||||||
url: dbData.database_url,
|
url: dbData.url,
|
||||||
database: dbData.database_database,
|
database: dbData.database,
|
||||||
extra: dbData.database_extra || {},
|
extra: dbData.extra || {},
|
||||||
schema: dbData.database_schema,
|
schema: dbData.schema,
|
||||||
entities,
|
entities,
|
||||||
logging: dbData.database_logging,
|
logging: dbData.logging,
|
||||||
} as DataSourceOptions)
|
} as DataSourceOptions)
|
||||||
|
|
||||||
await dataSource.initialize()
|
await dataSource.initialize()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { InternalModuleDeclaration, LoaderOptions } from "@medusajs/modules-sdk"
|
|||||||
import {
|
import {
|
||||||
InventoryItemService,
|
InventoryItemService,
|
||||||
InventoryLevelService,
|
InventoryLevelService,
|
||||||
ReservationItemService,
|
ReservationItemService
|
||||||
} from "../services"
|
} from "../services"
|
||||||
|
|
||||||
import { asClass } from "awilix"
|
import { asClass } from "awilix"
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { InternalModuleDeclaration, LoaderOptions } from "@medusajs/modules-sdk"
|
||||||
|
import { DataSource, DataSourceOptions } from "typeorm"
|
||||||
|
import { InventoryServiceInitializeOptions } from "../types"
|
||||||
|
|
||||||
|
import migrations from "./index"
|
||||||
|
|
||||||
|
function getDataSource(
|
||||||
|
dbData: InventoryServiceInitializeOptions["database"]
|
||||||
|
): DataSource {
|
||||||
|
return new DataSource({
|
||||||
|
type: dbData!.type,
|
||||||
|
url: dbData!.url,
|
||||||
|
database: dbData!.database,
|
||||||
|
extra: dbData!.extra || {},
|
||||||
|
migrations: migrations
|
||||||
|
.map((migration: any): Function[] => {
|
||||||
|
return Object.values(migration).filter(
|
||||||
|
(fn) => typeof fn === "function"
|
||||||
|
) as Function[]
|
||||||
|
})
|
||||||
|
.flat(),
|
||||||
|
schema: dbData!.schema,
|
||||||
|
logging: dbData!.logging,
|
||||||
|
} as DataSourceOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function runMigrations(
|
||||||
|
{ options, logger }: Omit<LoaderOptions, "container">,
|
||||||
|
moduleDeclaration?: InternalModuleDeclaration
|
||||||
|
) {
|
||||||
|
const dbData =
|
||||||
|
options?.database as InventoryServiceInitializeOptions["database"]
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dataSource = getDataSource(dbData)
|
||||||
|
await dataSource.initialize()
|
||||||
|
await dataSource.runMigrations()
|
||||||
|
|
||||||
|
logger?.info("Inventory module migration executed")
|
||||||
|
} catch (error) {
|
||||||
|
logger?.error(`Inventory module migration failed to run - Error: ${error}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function revertMigration(
|
||||||
|
{ options, logger }: Omit<LoaderOptions, "container">,
|
||||||
|
moduleDeclaration?: InternalModuleDeclaration
|
||||||
|
) {
|
||||||
|
const dbData =
|
||||||
|
options?.database as InventoryServiceInitializeOptions["database"]
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dataSource = getDataSource(dbData)
|
||||||
|
await dataSource.initialize()
|
||||||
|
await dataSource.undoLastMigration()
|
||||||
|
|
||||||
|
logger?.info("Inventory module migration reverted")
|
||||||
|
} catch (error) {
|
||||||
|
logger?.error(
|
||||||
|
`Inventory module migration failed to revert - Error: ${error}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Index, Unique, BeforeInsert, Column, Entity } from "typeorm"
|
import { Index, BeforeInsert, Column, Entity } from "typeorm"
|
||||||
import { SoftDeletableEntity, generateEntityId } from "@medusajs/medusa"
|
import { SoftDeletableEntity, generateEntityId } from "@medusajs/medusa"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { DeepPartial, EntityManager, FindManyOptions } from "typeorm"
|
|
||||||
import { isDefined, MedusaError } from "medusa-core-utils"
|
|
||||||
import {
|
import {
|
||||||
buildQuery,
|
buildQuery,
|
||||||
CreateInventoryItemInput,
|
CreateInventoryItemInput,
|
||||||
@@ -7,9 +5,11 @@ import {
|
|||||||
FindConfig,
|
FindConfig,
|
||||||
IEventBusService,
|
IEventBusService,
|
||||||
InventoryItemDTO,
|
InventoryItemDTO,
|
||||||
TransactionBaseService,
|
|
||||||
} from "@medusajs/medusa"
|
} from "@medusajs/medusa"
|
||||||
|
import { SharedContext } from "@medusajs/types"
|
||||||
|
import { InjectEntityManager, MedusaContext } from "@medusajs/utils"
|
||||||
|
import { isDefined, MedusaError } from "medusa-core-utils"
|
||||||
|
import { DeepPartial, EntityManager, FindManyOptions } from "typeorm"
|
||||||
import { InventoryItem } from "../models"
|
import { InventoryItem } from "../models"
|
||||||
import { getListQuery } from "../utils/query"
|
import { getListQuery } from "../utils/query"
|
||||||
|
|
||||||
@@ -18,18 +18,18 @@ type InjectedDependencies = {
|
|||||||
manager: EntityManager
|
manager: EntityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class InventoryItemService extends TransactionBaseService {
|
export default class InventoryItemService {
|
||||||
static Events = {
|
static Events = {
|
||||||
CREATED: "inventory-item.created",
|
CREATED: "inventory-item.created",
|
||||||
UPDATED: "inventory-item.updated",
|
UPDATED: "inventory-item.updated",
|
||||||
DELETED: "inventory-item.deleted",
|
DELETED: "inventory-item.deleted",
|
||||||
}
|
}
|
||||||
|
|
||||||
protected readonly eventBusService_: IEventBusService
|
protected readonly manager_: EntityManager
|
||||||
|
protected readonly eventBusService_: IEventBusService | undefined
|
||||||
constructor({ eventBusService }: InjectedDependencies) {
|
|
||||||
super(arguments[0])
|
|
||||||
|
|
||||||
|
constructor({ eventBusService, manager }: InjectedDependencies) {
|
||||||
|
this.manager_ = manager
|
||||||
this.eventBusService_ = eventBusService
|
this.eventBusService_ = eventBusService
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,11 +38,17 @@ export default class InventoryItemService extends TransactionBaseService {
|
|||||||
* @param config - Configuration for query.
|
* @param config - Configuration for query.
|
||||||
* @return Resolves to the list of inventory items that match the filter.
|
* @return Resolves to the list of inventory items that match the filter.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async list(
|
async list(
|
||||||
selector: FilterableInventoryItemProps = {},
|
selector: FilterableInventoryItemProps = {},
|
||||||
config: FindConfig<InventoryItem> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<InventoryItem> = { relations: [], skip: 0, take: 10 },
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryItemDTO[]> {
|
): Promise<InventoryItemDTO[]> {
|
||||||
const queryBuilder = getListQuery(this.activeManager_, selector, config)
|
const queryBuilder = getListQuery(
|
||||||
|
context.transactionManager!,
|
||||||
|
selector,
|
||||||
|
config
|
||||||
|
)
|
||||||
return await queryBuilder.getMany()
|
return await queryBuilder.getMany()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,11 +57,17 @@ export default class InventoryItemService extends TransactionBaseService {
|
|||||||
* @param config - Configuration for query.
|
* @param config - Configuration for query.
|
||||||
* @return - Resolves to the list of inventory items that match the filter and the count of all matching items.
|
* @return - Resolves to the list of inventory items that match the filter and the count of all matching items.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async listAndCount(
|
async listAndCount(
|
||||||
selector: FilterableInventoryItemProps = {},
|
selector: FilterableInventoryItemProps = {},
|
||||||
config: FindConfig<InventoryItem> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<InventoryItem> = { relations: [], skip: 0, take: 10 },
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<[InventoryItemDTO[], number]> {
|
): Promise<[InventoryItemDTO[], number]> {
|
||||||
const queryBuilder = getListQuery(this.activeManager_, selector, config)
|
const queryBuilder = getListQuery(
|
||||||
|
context.transactionManager!,
|
||||||
|
selector,
|
||||||
|
config
|
||||||
|
)
|
||||||
return await queryBuilder.getManyAndCount()
|
return await queryBuilder.getManyAndCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,9 +78,11 @@ export default class InventoryItemService extends TransactionBaseService {
|
|||||||
* @return The retrieved inventory item.
|
* @return The retrieved inventory item.
|
||||||
* @throws If the inventory item id is not defined or if the inventory item is not found.
|
* @throws If the inventory item id is not defined or if the inventory item is not found.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async retrieve(
|
async retrieve(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
config: FindConfig<InventoryItem> = {}
|
config: FindConfig<InventoryItem> = {},
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryItem> {
|
): Promise<InventoryItem> {
|
||||||
if (!isDefined(inventoryItemId)) {
|
if (!isDefined(inventoryItemId)) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -77,7 +91,7 @@ export default class InventoryItemService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const itemRepository = manager.getRepository(InventoryItem)
|
const itemRepository = manager.getRepository(InventoryItem)
|
||||||
|
|
||||||
const query = buildQuery({ id: inventoryItemId }, config) as FindManyOptions
|
const query = buildQuery({ id: inventoryItemId }, config) as FindManyOptions
|
||||||
@@ -97,34 +111,35 @@ export default class InventoryItemService extends TransactionBaseService {
|
|||||||
* @param input - Input for creating a new inventory item.
|
* @param input - Input for creating a new inventory item.
|
||||||
* @return The newly created inventory item.
|
* @return The newly created inventory item.
|
||||||
*/
|
*/
|
||||||
async create(data: CreateInventoryItemInput): Promise<InventoryItem> {
|
@InjectEntityManager()
|
||||||
return await this.atomicPhase_(async (manager) => {
|
async create(
|
||||||
const itemRepository = manager.getRepository(InventoryItem)
|
data: CreateInventoryItemInput,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<InventoryItem> {
|
||||||
|
const manager = context.transactionManager!
|
||||||
|
const itemRepository = manager.getRepository(InventoryItem)
|
||||||
|
|
||||||
const inventoryItem = itemRepository.create({
|
const inventoryItem = itemRepository.create({
|
||||||
sku: data.sku,
|
sku: data.sku,
|
||||||
origin_country: data.origin_country,
|
origin_country: data.origin_country,
|
||||||
metadata: data.metadata,
|
metadata: data.metadata,
|
||||||
hs_code: data.hs_code,
|
hs_code: data.hs_code,
|
||||||
mid_code: data.mid_code,
|
mid_code: data.mid_code,
|
||||||
material: data.material,
|
material: data.material,
|
||||||
weight: data.weight,
|
weight: data.weight,
|
||||||
length: data.length,
|
length: data.length,
|
||||||
height: data.height,
|
height: data.height,
|
||||||
width: data.width,
|
width: data.width,
|
||||||
requires_shipping: data.requires_shipping,
|
requires_shipping: data.requires_shipping,
|
||||||
})
|
|
||||||
|
|
||||||
const result = await itemRepository.save(inventoryItem)
|
|
||||||
|
|
||||||
await this.eventBusService_
|
|
||||||
.withTransaction(manager)
|
|
||||||
.emit(InventoryItemService.Events.CREATED, {
|
|
||||||
id: result.id,
|
|
||||||
})
|
|
||||||
|
|
||||||
return result
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const result = await itemRepository.save(inventoryItem)
|
||||||
|
|
||||||
|
await this.eventBusService_?.emit?.(InventoryItemService.Events.CREATED, {
|
||||||
|
id: result.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,51 +147,51 @@ export default class InventoryItemService extends TransactionBaseService {
|
|||||||
* @param update - The updates to apply to the inventory item.
|
* @param update - The updates to apply to the inventory item.
|
||||||
* @return The updated inventory item.
|
* @return The updated inventory item.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async update(
|
async update(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
data: Omit<
|
data: Omit<
|
||||||
DeepPartial<InventoryItem>,
|
DeepPartial<InventoryItem>,
|
||||||
"id" | "created_at" | "metadata" | "deleted_at"
|
"id" | "created_at" | "metadata" | "deleted_at"
|
||||||
>
|
>,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryItem> {
|
): Promise<InventoryItem> {
|
||||||
return await this.atomicPhase_(async (manager) => {
|
const manager = context.transactionManager!
|
||||||
const itemRepository = manager.getRepository(InventoryItem)
|
const itemRepository = manager.getRepository(InventoryItem)
|
||||||
|
|
||||||
const item = await this.retrieve(inventoryItemId)
|
const item = await this.retrieve(inventoryItemId, undefined, context)
|
||||||
|
|
||||||
const shouldUpdate = Object.keys(data).some((key) => {
|
const shouldUpdate = Object.keys(data).some((key) => {
|
||||||
return item[key] !== data[key]
|
return item[key] !== data[key]
|
||||||
})
|
|
||||||
|
|
||||||
if (shouldUpdate) {
|
|
||||||
itemRepository.merge(item, data)
|
|
||||||
await itemRepository.save(item)
|
|
||||||
|
|
||||||
await this.eventBusService_
|
|
||||||
.withTransaction(manager)
|
|
||||||
.emit(InventoryItemService.Events.UPDATED, {
|
|
||||||
id: item.id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return item
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (shouldUpdate) {
|
||||||
|
itemRepository.merge(item, data)
|
||||||
|
await itemRepository.save(item)
|
||||||
|
|
||||||
|
await this.eventBusService_?.emit?.(InventoryItemService.Events.UPDATED, {
|
||||||
|
id: item.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param inventoryItemId - The id of the inventory item to delete.
|
* @param inventoryItemId - The id of the inventory item to delete.
|
||||||
*/
|
*/
|
||||||
async delete(inventoryItemId: string): Promise<void> {
|
@InjectEntityManager()
|
||||||
await this.atomicPhase_(async (manager) => {
|
async delete(
|
||||||
const itemRepository = manager.getRepository(InventoryItem)
|
inventoryItemId: string,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const manager = context.transactionManager!
|
||||||
|
const itemRepository = manager.getRepository(InventoryItem)
|
||||||
|
|
||||||
await itemRepository.softRemove({ id: inventoryItemId })
|
await itemRepository.softRemove({ id: inventoryItemId })
|
||||||
|
|
||||||
await this.eventBusService_
|
await this.eventBusService_?.emit?.(InventoryItemService.Events.DELETED, {
|
||||||
.withTransaction(manager)
|
id: inventoryItemId,
|
||||||
.emit(InventoryItemService.Events.DELETED, {
|
|
||||||
id: inventoryItemId,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { DeepPartial, EntityManager, FindManyOptions, In } from "typeorm"
|
|
||||||
import { isDefined, MedusaError } from "medusa-core-utils"
|
|
||||||
import {
|
import {
|
||||||
buildQuery,
|
buildQuery,
|
||||||
CreateInventoryLevelInput,
|
CreateInventoryLevelInput,
|
||||||
FilterableInventoryLevelProps,
|
FilterableInventoryLevelProps,
|
||||||
FindConfig,
|
FindConfig,
|
||||||
IEventBusService,
|
IEventBusService,
|
||||||
TransactionBaseService,
|
|
||||||
} from "@medusajs/medusa"
|
} from "@medusajs/medusa"
|
||||||
|
import { SharedContext } from "@medusajs/types"
|
||||||
|
import { InjectEntityManager, MedusaContext } from "@medusajs/utils"
|
||||||
|
import { isDefined, MedusaError } from "medusa-core-utils"
|
||||||
|
import { DeepPartial, EntityManager, FindManyOptions, In } from "typeorm"
|
||||||
import { InventoryLevel } from "../models"
|
import { InventoryLevel } from "../models"
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
@@ -16,18 +16,18 @@ type InjectedDependencies = {
|
|||||||
manager: EntityManager
|
manager: EntityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class InventoryLevelService extends TransactionBaseService {
|
export default class InventoryLevelService {
|
||||||
static Events = {
|
static Events = {
|
||||||
CREATED: "inventory-level.created",
|
CREATED: "inventory-level.created",
|
||||||
UPDATED: "inventory-level.updated",
|
UPDATED: "inventory-level.updated",
|
||||||
DELETED: "inventory-level.deleted",
|
DELETED: "inventory-level.deleted",
|
||||||
}
|
}
|
||||||
|
|
||||||
protected readonly eventBusService_: IEventBusService
|
protected readonly manager_: EntityManager
|
||||||
|
protected readonly eventBusService_: IEventBusService | undefined
|
||||||
constructor({ eventBusService }: InjectedDependencies) {
|
|
||||||
super(arguments[0])
|
|
||||||
|
|
||||||
|
constructor({ eventBusService, manager }: InjectedDependencies) {
|
||||||
|
this.manager_ = manager
|
||||||
this.eventBusService_ = eventBusService
|
this.eventBusService_ = eventBusService
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,11 +37,13 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* @param config - An object containing configuration options for the query.
|
* @param config - An object containing configuration options for the query.
|
||||||
* @return Array of inventory levels.
|
* @return Array of inventory levels.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async list(
|
async list(
|
||||||
selector: FilterableInventoryLevelProps = {},
|
selector: FilterableInventoryLevelProps = {},
|
||||||
config: FindConfig<InventoryLevel> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<InventoryLevel> = { relations: [], skip: 0, take: 10 },
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryLevel[]> {
|
): Promise<InventoryLevel[]> {
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
const query = buildQuery(selector, config) as FindManyOptions
|
const query = buildQuery(selector, config) as FindManyOptions
|
||||||
@@ -54,11 +56,13 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* @param config - An object containing configuration options for the query.
|
* @param config - An object containing configuration options for the query.
|
||||||
* @return An array of inventory levels and a count.
|
* @return An array of inventory levels and a count.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async listAndCount(
|
async listAndCount(
|
||||||
selector: FilterableInventoryLevelProps = {},
|
selector: FilterableInventoryLevelProps = {},
|
||||||
config: FindConfig<InventoryLevel> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<InventoryLevel> = { relations: [], skip: 0, take: 10 },
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<[InventoryLevel[], number]> {
|
): Promise<[InventoryLevel[], number]> {
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
const query = buildQuery(selector, config) as FindManyOptions
|
const query = buildQuery(selector, config) as FindManyOptions
|
||||||
@@ -72,9 +76,11 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* @return A inventory level.
|
* @return A inventory level.
|
||||||
* @throws If the inventory level ID is not defined or the given ID was not found.
|
* @throws If the inventory level ID is not defined or the given ID was not found.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async retrieve(
|
async retrieve(
|
||||||
inventoryLevelId: string,
|
inventoryLevelId: string,
|
||||||
config: FindConfig<InventoryLevel> = {}
|
config: FindConfig<InventoryLevel> = {},
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryLevel> {
|
): Promise<InventoryLevel> {
|
||||||
if (!isDefined(inventoryLevelId)) {
|
if (!isDefined(inventoryLevelId)) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -83,10 +89,13 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
const query = buildQuery({ id: inventoryLevelId }, config) as FindManyOptions
|
const query = buildQuery(
|
||||||
|
{ id: inventoryLevelId },
|
||||||
|
config
|
||||||
|
) as FindManyOptions
|
||||||
const [inventoryLevel] = await levelRepository.find(query)
|
const [inventoryLevel] = await levelRepository.find(query)
|
||||||
|
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
@@ -104,27 +113,29 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* @param data - An object containing the properties for the new inventory level.
|
* @param data - An object containing the properties for the new inventory level.
|
||||||
* @return The created inventory level.
|
* @return The created inventory level.
|
||||||
*/
|
*/
|
||||||
async create(data: CreateInventoryLevelInput): Promise<InventoryLevel> {
|
@InjectEntityManager()
|
||||||
return await this.atomicPhase_(async (manager) => {
|
async create(
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
data: CreateInventoryLevelInput,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<InventoryLevel> {
|
||||||
|
const manager = context.transactionManager!
|
||||||
|
|
||||||
const inventoryLevel = levelRepository.create({
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
location_id: data.location_id,
|
|
||||||
inventory_item_id: data.inventory_item_id,
|
|
||||||
stocked_quantity: data.stocked_quantity,
|
|
||||||
reserved_quantity: data.reserved_quantity,
|
|
||||||
incoming_quantity: data.incoming_quantity,
|
|
||||||
})
|
|
||||||
|
|
||||||
const saved = await levelRepository.save(inventoryLevel)
|
const inventoryLevel = levelRepository.create({
|
||||||
await this.eventBusService_
|
location_id: data.location_id,
|
||||||
.withTransaction(manager)
|
inventory_item_id: data.inventory_item_id,
|
||||||
.emit(InventoryLevelService.Events.CREATED, {
|
stocked_quantity: data.stocked_quantity,
|
||||||
id: saved.id,
|
reserved_quantity: data.reserved_quantity,
|
||||||
})
|
incoming_quantity: data.incoming_quantity,
|
||||||
|
|
||||||
return saved
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const saved = await levelRepository.save(inventoryLevel)
|
||||||
|
await this.eventBusService_?.emit?.(InventoryLevelService.Events.CREATED, {
|
||||||
|
id: saved.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
return saved
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,35 +145,37 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* @return The updated inventory level.
|
* @return The updated inventory level.
|
||||||
* @throws If the inventory level ID is not defined or the given ID was not found.
|
* @throws If the inventory level ID is not defined or the given ID was not found.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async update(
|
async update(
|
||||||
inventoryLevelId: string,
|
inventoryLevelId: string,
|
||||||
data: Omit<
|
data: Omit<
|
||||||
DeepPartial<InventoryLevel>,
|
DeepPartial<InventoryLevel>,
|
||||||
"id" | "created_at" | "metadata" | "deleted_at"
|
"id" | "created_at" | "metadata" | "deleted_at"
|
||||||
>
|
>,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryLevel> {
|
): Promise<InventoryLevel> {
|
||||||
return await this.atomicPhase_(async (manager) => {
|
const manager = context.transactionManager!
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
const item = await this.retrieve(inventoryLevelId)
|
const item = await this.retrieve(inventoryLevelId, undefined, context)
|
||||||
|
|
||||||
const shouldUpdate = Object.keys(data).some((key) => {
|
const shouldUpdate = Object.keys(data).some((key) => {
|
||||||
return item[key] !== data[key]
|
return item[key] !== data[key]
|
||||||
})
|
|
||||||
|
|
||||||
if (shouldUpdate) {
|
|
||||||
levelRepository.merge(item, data)
|
|
||||||
await levelRepository.save(item)
|
|
||||||
|
|
||||||
await this.eventBusService_
|
|
||||||
.withTransaction(manager)
|
|
||||||
.emit(InventoryLevelService.Events.UPDATED, {
|
|
||||||
id: item.id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return item
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (shouldUpdate) {
|
||||||
|
levelRepository.merge(item, data)
|
||||||
|
await levelRepository.save(item)
|
||||||
|
|
||||||
|
await this.eventBusService_?.emit?.(
|
||||||
|
InventoryLevelService.Events.UPDATED,
|
||||||
|
{
|
||||||
|
id: item.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -171,40 +184,45 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* @param locationId - The ID of the location.
|
* @param locationId - The ID of the location.
|
||||||
* @param quantity - The quantity to adjust from the reserved quantity.
|
* @param quantity - The quantity to adjust from the reserved quantity.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async adjustReservedQuantity(
|
async adjustReservedQuantity(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationId: string,
|
locationId: string,
|
||||||
quantity: number
|
quantity: number,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.atomicPhase_(async (manager) => {
|
const manager = context.transactionManager!
|
||||||
await manager
|
await manager
|
||||||
.createQueryBuilder()
|
.createQueryBuilder()
|
||||||
.update(InventoryLevel)
|
.update(InventoryLevel)
|
||||||
.set({ reserved_quantity: () => `reserved_quantity + ${quantity}` })
|
.set({ reserved_quantity: () => `reserved_quantity + ${quantity}` })
|
||||||
.where(
|
.where(
|
||||||
"inventory_item_id = :inventoryItemId AND location_id = :locationId",
|
"inventory_item_id = :inventoryItemId AND location_id = :locationId",
|
||||||
{ inventoryItemId, locationId }
|
{ inventoryItemId, locationId }
|
||||||
)
|
)
|
||||||
.execute()
|
.execute()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes inventory levels by inventory Item ID.
|
* Deletes inventory levels by inventory Item ID.
|
||||||
* @param inventoryItemId - The ID or IDs of the inventory item to delete inventory levels for.
|
* @param inventoryItemId - The ID or IDs of the inventory item to delete inventory levels for.
|
||||||
*/
|
*/
|
||||||
async deleteByInventoryItemId(inventoryItemId: string | string[]): Promise<void> {
|
@InjectEntityManager()
|
||||||
const ids = Array.isArray(inventoryItemId) ? inventoryItemId : [inventoryItemId]
|
async deleteByInventoryItemId(
|
||||||
await this.atomicPhase_(async (manager) => {
|
inventoryItemId: string | string[],
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const ids = Array.isArray(inventoryItemId)
|
||||||
|
? inventoryItemId
|
||||||
|
: [inventoryItemId]
|
||||||
|
|
||||||
await levelRepository.delete({ inventory_item_id: In(ids) })
|
const manager = context.transactionManager!
|
||||||
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
await this.eventBusService_
|
await levelRepository.delete({ inventory_item_id: In(ids) })
|
||||||
.withTransaction(manager)
|
|
||||||
.emit(InventoryLevelService.Events.DELETED, {
|
await this.eventBusService_?.emit?.(InventoryLevelService.Events.DELETED, {
|
||||||
inventory_item_id: inventoryItemId,
|
inventory_item_id: inventoryItemId,
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,18 +230,22 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* Deletes an inventory level by ID.
|
* Deletes an inventory level by ID.
|
||||||
* @param inventoryLevelId - The ID or IDs of the inventory level to delete.
|
* @param inventoryLevelId - The ID or IDs of the inventory level to delete.
|
||||||
*/
|
*/
|
||||||
async delete(inventoryLevelId: string | string[]): Promise<void> {
|
@InjectEntityManager()
|
||||||
const ids = Array.isArray(inventoryLevelId) ? inventoryLevelId : [inventoryLevelId]
|
async delete(
|
||||||
await this.atomicPhase_(async (manager) => {
|
inventoryLevelId: string | string[],
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const ids = Array.isArray(inventoryLevelId)
|
||||||
|
? inventoryLevelId
|
||||||
|
: [inventoryLevelId]
|
||||||
|
|
||||||
await levelRepository.delete({ id: In(ids) })
|
const manager = context.transactionManager!
|
||||||
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
await this.eventBusService_
|
await levelRepository.delete({ id: In(ids) })
|
||||||
.withTransaction(manager)
|
|
||||||
.emit(InventoryLevelService.Events.DELETED, {
|
await this.eventBusService_?.emit?.(InventoryLevelService.Events.DELETED, {
|
||||||
id: inventoryLevelId,
|
id: inventoryLevelId,
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,17 +253,18 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* Deletes inventory levels by location ID.
|
* Deletes inventory levels by location ID.
|
||||||
* @param locationId - The ID of the location to delete inventory levels for.
|
* @param locationId - The ID of the location to delete inventory levels for.
|
||||||
*/
|
*/
|
||||||
async deleteByLocationId(locationId: string): Promise<void> {
|
@InjectEntityManager()
|
||||||
return await this.atomicPhase_(async (manager) => {
|
async deleteByLocationId(
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
locationId: string,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const manager = context.transactionManager!
|
||||||
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
await levelRepository.delete({ location_id: locationId })
|
await levelRepository.delete({ location_id: locationId })
|
||||||
|
|
||||||
await this.eventBusService_
|
await this.eventBusService_?.emit?.(InventoryLevelService.Events.DELETED, {
|
||||||
.withTransaction(manager)
|
location_id: locationId,
|
||||||
.emit(InventoryLevelService.Events.DELETED, {
|
|
||||||
location_id: locationId,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,15 +274,17 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* @param locationIds - The IDs of the locations.
|
* @param locationIds - The IDs of the locations.
|
||||||
* @return The total stocked quantity.
|
* @return The total stocked quantity.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async getStockedQuantity(
|
async getStockedQuantity(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationIds: string[] | string
|
locationIds: string[] | string,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
if (!Array.isArray(locationIds)) {
|
if (!Array.isArray(locationIds)) {
|
||||||
locationIds = [locationIds]
|
locationIds = [locationIds]
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
const result = await levelRepository
|
const result = await levelRepository
|
||||||
@@ -278,15 +303,17 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* @param locationIds - The IDs of the locations.
|
* @param locationIds - The IDs of the locations.
|
||||||
* @return The total available quantity.
|
* @return The total available quantity.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async getAvailableQuantity(
|
async getAvailableQuantity(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationIds: string[] | string
|
locationIds: string[] | string,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
if (!Array.isArray(locationIds)) {
|
if (!Array.isArray(locationIds)) {
|
||||||
locationIds = [locationIds]
|
locationIds = [locationIds]
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
const result = await levelRepository
|
const result = await levelRepository
|
||||||
@@ -305,15 +332,17 @@ export default class InventoryLevelService extends TransactionBaseService {
|
|||||||
* @param locationIds - The IDs of the locations.
|
* @param locationIds - The IDs of the locations.
|
||||||
* @return The total reserved quantity.
|
* @return The total reserved quantity.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async getReservedQuantity(
|
async getReservedQuantity(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationIds: string[] | string
|
locationIds: string[] | string,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
if (!Array.isArray(locationIds)) {
|
if (!Array.isArray(locationIds)) {
|
||||||
locationIds = [locationIds]
|
locationIds = [locationIds]
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const levelRepository = manager.getRepository(InventoryLevel)
|
const levelRepository = manager.getRepository(InventoryLevel)
|
||||||
|
|
||||||
const result = await levelRepository
|
const result = await levelRepository
|
||||||
|
|||||||
@@ -13,18 +13,18 @@ import {
|
|||||||
InventoryItemDTO,
|
InventoryItemDTO,
|
||||||
InventoryLevelDTO,
|
InventoryLevelDTO,
|
||||||
ReservationItemDTO,
|
ReservationItemDTO,
|
||||||
TransactionBaseService,
|
|
||||||
UpdateInventoryLevelInput,
|
UpdateInventoryLevelInput,
|
||||||
UpdateReservationItemInput,
|
UpdateReservationItemInput,
|
||||||
} from "@medusajs/medusa"
|
} from "@medusajs/medusa"
|
||||||
|
import { SharedContext } from "@medusajs/types"
|
||||||
|
import { InjectEntityManager, MedusaContext } from "@medusajs/utils"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
import { EntityManager } from "typeorm"
|
||||||
import {
|
import {
|
||||||
InventoryItemService,
|
InventoryItemService,
|
||||||
InventoryLevelService,
|
InventoryLevelService,
|
||||||
ReservationItemService,
|
ReservationItemService,
|
||||||
} from "./"
|
} from "./"
|
||||||
import { EntityManager } from "typeorm"
|
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
manager: EntityManager
|
manager: EntityManager
|
||||||
@@ -33,11 +33,9 @@ type InjectedDependencies = {
|
|||||||
inventoryLevelService: InventoryLevelService
|
inventoryLevelService: InventoryLevelService
|
||||||
reservationItemService: ReservationItemService
|
reservationItemService: ReservationItemService
|
||||||
}
|
}
|
||||||
export default class InventoryService
|
export default class InventoryService implements IInventoryService {
|
||||||
extends TransactionBaseService
|
protected readonly manager_: EntityManager
|
||||||
implements IInventoryService
|
protected readonly eventBusService_: IEventBusService | undefined
|
||||||
{
|
|
||||||
protected readonly eventBusService_: IEventBusService
|
|
||||||
protected readonly inventoryItemService_: InventoryItemService
|
protected readonly inventoryItemService_: InventoryItemService
|
||||||
protected readonly reservationItemService_: ReservationItemService
|
protected readonly reservationItemService_: ReservationItemService
|
||||||
protected readonly inventoryLevelService_: InventoryLevelService
|
protected readonly inventoryLevelService_: InventoryLevelService
|
||||||
@@ -53,9 +51,7 @@ export default class InventoryService
|
|||||||
options?: unknown,
|
options?: unknown,
|
||||||
moduleDeclaration?: InternalModuleDeclaration
|
moduleDeclaration?: InternalModuleDeclaration
|
||||||
) {
|
) {
|
||||||
// @ts-ignore
|
this.manager_ = manager
|
||||||
super(...arguments)
|
|
||||||
|
|
||||||
this.eventBusService_ = eventBusService
|
this.eventBusService_ = eventBusService
|
||||||
this.inventoryItemService_ = inventoryItemService
|
this.inventoryItemService_ = inventoryItemService
|
||||||
this.inventoryLevelService_ = inventoryLevelService
|
this.inventoryLevelService_ = inventoryLevelService
|
||||||
@@ -68,13 +64,17 @@ export default class InventoryService
|
|||||||
* @param config - the find configuration to use
|
* @param config - the find configuration to use
|
||||||
* @return A tuple of inventory items and their total count
|
* @return A tuple of inventory items and their total count
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async listInventoryItems(
|
async listInventoryItems(
|
||||||
selector: FilterableInventoryItemProps,
|
selector: FilterableInventoryItemProps,
|
||||||
config: FindConfig<InventoryItemDTO> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<InventoryItemDTO> = { relations: [], skip: 0, take: 10 },
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<[InventoryItemDTO[], number]> {
|
): Promise<[InventoryItemDTO[], number]> {
|
||||||
return await this.inventoryItemService_
|
return await this.inventoryItemService_.listAndCount(
|
||||||
.withTransaction(this.activeManager_)
|
selector,
|
||||||
.listAndCount(selector, config)
|
config,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,13 +83,21 @@ export default class InventoryService
|
|||||||
* @param config - the find configuration to use
|
* @param config - the find configuration to use
|
||||||
* @return A tuple of inventory levels and their total count
|
* @return A tuple of inventory levels and their total count
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async listInventoryLevels(
|
async listInventoryLevels(
|
||||||
selector: FilterableInventoryLevelProps,
|
selector: FilterableInventoryLevelProps,
|
||||||
config: FindConfig<InventoryLevelDTO> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<InventoryLevelDTO> = {
|
||||||
|
relations: [],
|
||||||
|
skip: 0,
|
||||||
|
take: 10,
|
||||||
|
},
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<[InventoryLevelDTO[], number]> {
|
): Promise<[InventoryLevelDTO[], number]> {
|
||||||
return await this.inventoryLevelService_
|
return await this.inventoryLevelService_.listAndCount(
|
||||||
.withTransaction(this.activeManager_)
|
selector,
|
||||||
.listAndCount(selector, config)
|
config,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,17 +106,21 @@ export default class InventoryService
|
|||||||
* @param config - the find configuration to use
|
* @param config - the find configuration to use
|
||||||
* @return A tuple of reservation items and their total count
|
* @return A tuple of reservation items and their total count
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async listReservationItems(
|
async listReservationItems(
|
||||||
selector: FilterableReservationItemProps,
|
selector: FilterableReservationItemProps,
|
||||||
config: FindConfig<ReservationItemDTO> = {
|
config: FindConfig<ReservationItemDTO> = {
|
||||||
relations: [],
|
relations: [],
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: 10,
|
take: 10,
|
||||||
}
|
},
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<[ReservationItemDTO[], number]> {
|
): Promise<[ReservationItemDTO[], number]> {
|
||||||
return await this.reservationItemService_
|
return await this.reservationItemService_.listAndCount(
|
||||||
.withTransaction(this.activeManager_)
|
selector,
|
||||||
.listAndCount(selector, config)
|
config,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,13 +129,17 @@ export default class InventoryService
|
|||||||
* @param config - the find configuration to use
|
* @param config - the find configuration to use
|
||||||
* @return The retrieved inventory item
|
* @return The retrieved inventory item
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async retrieveInventoryItem(
|
async retrieveInventoryItem(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
config?: FindConfig<InventoryItemDTO>
|
config?: FindConfig<InventoryItemDTO>,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryItemDTO> {
|
): Promise<InventoryItemDTO> {
|
||||||
const inventoryItem = await this.inventoryItemService_
|
const inventoryItem = await this.inventoryItemService_.retrieve(
|
||||||
.withTransaction(this.activeManager_)
|
inventoryItemId,
|
||||||
.retrieve(inventoryItemId, config)
|
config,
|
||||||
|
context
|
||||||
|
)
|
||||||
return { ...inventoryItem }
|
return { ...inventoryItem }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,16 +149,17 @@ export default class InventoryService
|
|||||||
* @param locationId - the id of the location
|
* @param locationId - the id of the location
|
||||||
* @return the retrieved inventory level
|
* @return the retrieved inventory level
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async retrieveInventoryLevel(
|
async retrieveInventoryLevel(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationId: string
|
locationId: string,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryLevelDTO> {
|
): Promise<InventoryLevelDTO> {
|
||||||
const [inventoryLevel] = await this.inventoryLevelService_
|
const [inventoryLevel] = await this.inventoryLevelService_.list(
|
||||||
.withTransaction(this.activeManager_)
|
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
||||||
.list(
|
{ take: 1 },
|
||||||
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
context
|
||||||
{ take: 1 }
|
)
|
||||||
)
|
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.NOT_FOUND,
|
MedusaError.Types.NOT_FOUND,
|
||||||
@@ -152,15 +169,21 @@ export default class InventoryService
|
|||||||
return inventoryLevel
|
return inventoryLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a reservation item
|
* Retrieves a reservation item
|
||||||
* @param inventoryItemId - the id of the reservation item
|
* @param inventoryItemId - the id of the reservation item
|
||||||
* @return the retrieved reservation level
|
* @return the retrieved reservation level
|
||||||
*/
|
*/
|
||||||
async retrieveReservationItem(reservationId: string): Promise<ReservationItemDTO> {
|
@InjectEntityManager()
|
||||||
return await this.reservationItemService_
|
async retrieveReservationItem(
|
||||||
.withTransaction(this.activeManager_)
|
reservationId: string,
|
||||||
.retrieve(reservationId)
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<ReservationItemDTO> {
|
||||||
|
return await this.reservationItemService_.retrieve(
|
||||||
|
reservationId,
|
||||||
|
undefined,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,19 +191,20 @@ export default class InventoryService
|
|||||||
* @param input - the input object
|
* @param input - the input object
|
||||||
* @return The created reservation item
|
* @return The created reservation item
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async createReservationItem(
|
async createReservationItem(
|
||||||
input: CreateReservationItemInput
|
input: CreateReservationItemInput,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<ReservationItemDTO> {
|
): Promise<ReservationItemDTO> {
|
||||||
// Verify that the item is stocked at the location
|
// Verify that the item is stocked at the location
|
||||||
const [inventoryLevel] = await this.inventoryLevelService_
|
const [inventoryLevel] = await this.inventoryLevelService_.list(
|
||||||
.withTransaction(this.activeManager_)
|
{
|
||||||
.list(
|
inventory_item_id: input.inventory_item_id,
|
||||||
{
|
location_id: input.location_id,
|
||||||
inventory_item_id: input.inventory_item_id,
|
},
|
||||||
location_id: input.location_id,
|
{ take: 1 },
|
||||||
},
|
context
|
||||||
{ take: 1 }
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -189,9 +213,10 @@ export default class InventoryService
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const reservationItem = await this.reservationItemService_
|
const reservationItem = await this.reservationItemService_.create(
|
||||||
.withTransaction(this.activeManager_)
|
input,
|
||||||
.create(input)
|
context
|
||||||
|
)
|
||||||
|
|
||||||
return { ...reservationItem }
|
return { ...reservationItem }
|
||||||
}
|
}
|
||||||
@@ -201,12 +226,15 @@ export default class InventoryService
|
|||||||
* @param input - the input object
|
* @param input - the input object
|
||||||
* @return The created inventory item
|
* @return The created inventory item
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async createInventoryItem(
|
async createInventoryItem(
|
||||||
input: CreateInventoryItemInput
|
input: CreateInventoryItemInput,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryItemDTO> {
|
): Promise<InventoryItemDTO> {
|
||||||
const inventoryItem = await this.inventoryItemService_
|
const inventoryItem = await this.inventoryItemService_.create(
|
||||||
.withTransaction(this.activeManager_)
|
input,
|
||||||
.create(input)
|
context
|
||||||
|
)
|
||||||
return { ...inventoryItem }
|
return { ...inventoryItem }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,12 +243,12 @@ export default class InventoryService
|
|||||||
* @param input - the input object
|
* @param input - the input object
|
||||||
* @return The created inventory level
|
* @return The created inventory level
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async createInventoryLevel(
|
async createInventoryLevel(
|
||||||
input: CreateInventoryLevelInput
|
input: CreateInventoryLevelInput,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryLevelDTO> {
|
): Promise<InventoryLevelDTO> {
|
||||||
return await this.inventoryLevelService_
|
return await this.inventoryLevelService_.create(input, context)
|
||||||
.withTransaction(this.activeManager_)
|
|
||||||
.create(input)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -229,13 +257,17 @@ export default class InventoryService
|
|||||||
* @param input - the input object
|
* @param input - the input object
|
||||||
* @return The updated inventory item
|
* @return The updated inventory item
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async updateInventoryItem(
|
async updateInventoryItem(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
input: Partial<CreateInventoryItemInput>
|
input: Partial<CreateInventoryItemInput>,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryItemDTO> {
|
): Promise<InventoryItemDTO> {
|
||||||
const inventoryItem = await this.inventoryItemService_
|
const inventoryItem = await this.inventoryItemService_.update(
|
||||||
.withTransaction(this.activeManager_)
|
inventoryItemId,
|
||||||
.update(inventoryItemId, input)
|
input,
|
||||||
|
context
|
||||||
|
)
|
||||||
return { ...inventoryItem }
|
return { ...inventoryItem }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,26 +275,39 @@ export default class InventoryService
|
|||||||
* Deletes an inventory item
|
* Deletes an inventory item
|
||||||
* @param inventoryItemId - the id of the inventory item to delete
|
* @param inventoryItemId - the id of the inventory item to delete
|
||||||
*/
|
*/
|
||||||
async deleteInventoryItem(inventoryItemId: string): Promise<void> {
|
@InjectEntityManager()
|
||||||
await this.inventoryLevelService_
|
async deleteInventoryItem(
|
||||||
.withTransaction(this.activeManager_)
|
inventoryItemId: string,
|
||||||
.deleteByInventoryItemId(inventoryItemId)
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
await this.inventoryLevelService_.deleteByInventoryItemId(
|
||||||
|
inventoryItemId,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
return await this.inventoryItemService_
|
return await this.inventoryItemService_.delete(inventoryItemId, context)
|
||||||
.withTransaction(this.activeManager_)
|
|
||||||
.delete(inventoryItemId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteInventoryItemLevelByLocationId(locationId: string): Promise<void> {
|
@InjectEntityManager()
|
||||||
return await this.inventoryLevelService_
|
async deleteInventoryItemLevelByLocationId(
|
||||||
.withTransaction(this.activeManager_)
|
locationId: string,
|
||||||
.deleteByLocationId(locationId)
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
return await this.inventoryLevelService_.deleteByLocationId(
|
||||||
|
locationId,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteReservationItemByLocationId(locationId: string): Promise<void> {
|
@InjectEntityManager()
|
||||||
return await this.reservationItemService_
|
async deleteReservationItemByLocationId(
|
||||||
.withTransaction(this.activeManager_)
|
locationId: string,
|
||||||
.deleteByLocationId(locationId)
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
return await this.reservationItemService_.deleteByLocationId(
|
||||||
|
locationId,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -270,24 +315,23 @@ export default class InventoryService
|
|||||||
* @param inventoryItemId - the id of the inventory item associated with the level
|
* @param inventoryItemId - the id of the inventory item associated with the level
|
||||||
* @param locationId - the id of the location associated with the level
|
* @param locationId - the id of the location associated with the level
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async deleteInventoryLevel(
|
async deleteInventoryLevel(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationId: string
|
locationId: string,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const [inventoryLevel] = await this.inventoryLevelService_
|
const [inventoryLevel] = await this.inventoryLevelService_.list(
|
||||||
.withTransaction(this.activeManager_)
|
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
||||||
.list(
|
{ take: 1 },
|
||||||
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
context
|
||||||
{ take: 1 }
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.inventoryLevelService_
|
return await this.inventoryLevelService_.delete(inventoryLevel.id, context)
|
||||||
.withTransaction(this.activeManager_)
|
|
||||||
.delete(inventoryLevel.id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -297,17 +341,18 @@ export default class InventoryService
|
|||||||
* @param input - the input object
|
* @param input - the input object
|
||||||
* @return The updated inventory level
|
* @return The updated inventory level
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async updateInventoryLevel(
|
async updateInventoryLevel(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationId: string,
|
locationId: string,
|
||||||
input: UpdateInventoryLevelInput
|
input: UpdateInventoryLevelInput,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryLevelDTO> {
|
): Promise<InventoryLevelDTO> {
|
||||||
const [inventoryLevel] = await this.inventoryLevelService_
|
const [inventoryLevel] = await this.inventoryLevelService_.list(
|
||||||
.withTransaction(this.activeManager_)
|
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
||||||
.list(
|
{ take: 1 },
|
||||||
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
context
|
||||||
{ take: 1 }
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -316,9 +361,11 @@ export default class InventoryService
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.inventoryLevelService_
|
return await this.inventoryLevelService_.update(
|
||||||
.withTransaction(this.activeManager_)
|
inventoryLevel.id,
|
||||||
.update(inventoryLevel.id, input)
|
input,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -327,33 +374,44 @@ export default class InventoryService
|
|||||||
* @param input - the input object
|
* @param input - the input object
|
||||||
* @return The updated inventory level
|
* @return The updated inventory level
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async updateReservationItem(
|
async updateReservationItem(
|
||||||
reservationItemId: string,
|
reservationItemId: string,
|
||||||
input: UpdateReservationItemInput
|
input: UpdateReservationItemInput,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<ReservationItemDTO> {
|
): Promise<ReservationItemDTO> {
|
||||||
return await this.reservationItemService_
|
return await this.reservationItemService_.update(
|
||||||
.withTransaction(this.activeManager_)
|
reservationItemId,
|
||||||
.update(reservationItemId, input)
|
input,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes reservation items by line item
|
* Deletes reservation items by line item
|
||||||
* @param lineItemId - the id of the line item associated with the reservation item
|
* @param lineItemId - the id of the line item associated with the reservation item
|
||||||
*/
|
*/
|
||||||
async deleteReservationItemsByLineItem(lineItemId: string): Promise<void> {
|
@InjectEntityManager()
|
||||||
return await this.reservationItemService_
|
async deleteReservationItemsByLineItem(
|
||||||
.withTransaction(this.activeManager_)
|
lineItemId: string,
|
||||||
.deleteByLineItem(lineItemId)
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
return await this.reservationItemService_.deleteByLineItem(
|
||||||
|
lineItemId,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a reservation item
|
* Deletes a reservation item
|
||||||
* @param reservationItemId - the id of the reservation item to delete
|
* @param reservationItemId - the id of the reservation item to delete
|
||||||
*/
|
*/
|
||||||
async deleteReservationItem(reservationItemId: string | string[]): Promise<void> {
|
@InjectEntityManager()
|
||||||
return await this.reservationItemService_
|
async deleteReservationItem(
|
||||||
.withTransaction(this.activeManager_)
|
reservationItemId: string | string[],
|
||||||
.delete(reservationItemId)
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
return await this.reservationItemService_.delete(reservationItemId, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -364,17 +422,18 @@ export default class InventoryService
|
|||||||
* @return The updated inventory level
|
* @return The updated inventory level
|
||||||
* @throws when the inventory level is not found
|
* @throws when the inventory level is not found
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async adjustInventory(
|
async adjustInventory(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationId: string,
|
locationId: string,
|
||||||
adjustment: number
|
adjustment: number,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<InventoryLevelDTO> {
|
): Promise<InventoryLevelDTO> {
|
||||||
const [inventoryLevel] = await this.inventoryLevelService_
|
const [inventoryLevel] = await this.inventoryLevelService_.list(
|
||||||
.withTransaction(this.activeManager_)
|
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
||||||
.list(
|
{ take: 1 },
|
||||||
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
context
|
||||||
{ take: 1 }
|
)
|
||||||
)
|
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.NOT_FOUND,
|
MedusaError.Types.NOT_FOUND,
|
||||||
@@ -382,11 +441,13 @@ export default class InventoryService
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedInventoryLevel = await this.inventoryLevelService_
|
const updatedInventoryLevel = await this.inventoryLevelService_.update(
|
||||||
.withTransaction(this.activeManager_)
|
inventoryLevel.id,
|
||||||
.update(inventoryLevel.id, {
|
{
|
||||||
stocked_quantity: inventoryLevel.stocked_quantity + adjustment,
|
stocked_quantity: inventoryLevel.stocked_quantity + adjustment,
|
||||||
})
|
},
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
return { ...updatedInventoryLevel }
|
return { ...updatedInventoryLevel }
|
||||||
}
|
}
|
||||||
@@ -398,20 +459,27 @@ export default class InventoryService
|
|||||||
* @return The available quantity
|
* @return The available quantity
|
||||||
* @throws when the inventory item is not found
|
* @throws when the inventory item is not found
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async retrieveAvailableQuantity(
|
async retrieveAvailableQuantity(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationIds: string[]
|
locationIds: string[],
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
// Throws if item does not exist
|
// Throws if item does not exist
|
||||||
await this.inventoryItemService_
|
await this.inventoryItemService_.retrieve(
|
||||||
.withTransaction(this.activeManager_)
|
inventoryItemId,
|
||||||
.retrieve(inventoryItemId, {
|
{
|
||||||
select: ["id"],
|
select: ["id"],
|
||||||
})
|
},
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
const availableQuantity = await this.inventoryLevelService_
|
const availableQuantity =
|
||||||
.withTransaction(this.activeManager_)
|
await this.inventoryLevelService_.getAvailableQuantity(
|
||||||
.getAvailableQuantity(inventoryItemId, locationIds)
|
inventoryItemId,
|
||||||
|
locationIds,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
return availableQuantity
|
return availableQuantity
|
||||||
}
|
}
|
||||||
@@ -423,20 +491,27 @@ export default class InventoryService
|
|||||||
* @return The stocked quantity
|
* @return The stocked quantity
|
||||||
* @throws when the inventory item is not found
|
* @throws when the inventory item is not found
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async retrieveStockedQuantity(
|
async retrieveStockedQuantity(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationIds: string[]
|
locationIds: string[],
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
// Throws if item does not exist
|
// Throws if item does not exist
|
||||||
await this.inventoryItemService_
|
await this.inventoryItemService_.retrieve(
|
||||||
.withTransaction(this.activeManager_)
|
inventoryItemId,
|
||||||
.retrieve(inventoryItemId, {
|
{
|
||||||
select: ["id"],
|
select: ["id"],
|
||||||
})
|
},
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
const stockedQuantity = await this.inventoryLevelService_
|
const stockedQuantity =
|
||||||
.withTransaction(this.activeManager_)
|
await this.inventoryLevelService_.getStockedQuantity(
|
||||||
.getStockedQuantity(inventoryItemId, locationIds)
|
inventoryItemId,
|
||||||
|
locationIds,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
return stockedQuantity
|
return stockedQuantity
|
||||||
}
|
}
|
||||||
@@ -448,20 +523,27 @@ export default class InventoryService
|
|||||||
* @return The reserved quantity
|
* @return The reserved quantity
|
||||||
* @throws when the inventory item is not found
|
* @throws when the inventory item is not found
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async retrieveReservedQuantity(
|
async retrieveReservedQuantity(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationIds: string[]
|
locationIds: string[],
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
// Throws if item does not exist
|
// Throws if item does not exist
|
||||||
await this.inventoryItemService_
|
await this.inventoryItemService_.retrieve(
|
||||||
.withTransaction(this.activeManager_)
|
inventoryItemId,
|
||||||
.retrieve(inventoryItemId, {
|
{
|
||||||
select: ["id"],
|
select: ["id"],
|
||||||
})
|
},
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
const reservedQuantity = await this.inventoryLevelService_
|
const reservedQuantity =
|
||||||
.withTransaction(this.activeManager_)
|
await this.inventoryLevelService_.getReservedQuantity(
|
||||||
.getReservedQuantity(inventoryItemId, locationIds)
|
inventoryItemId,
|
||||||
|
locationIds,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
return reservedQuantity
|
return reservedQuantity
|
||||||
}
|
}
|
||||||
@@ -473,14 +555,17 @@ export default class InventoryService
|
|||||||
* @param quantity - the quantity to check
|
* @param quantity - the quantity to check
|
||||||
* @return Whether there is sufficient inventory
|
* @return Whether there is sufficient inventory
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async confirmInventory(
|
async confirmInventory(
|
||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationIds: string[],
|
locationIds: string[],
|
||||||
quantity: number
|
quantity: number,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const availableQuantity = await this.retrieveAvailableQuantity(
|
const availableQuantity = await this.retrieveAvailableQuantity(
|
||||||
inventoryItemId,
|
inventoryItemId,
|
||||||
locationIds
|
locationIds,
|
||||||
|
context
|
||||||
)
|
)
|
||||||
return availableQuantity >= quantity
|
return availableQuantity >= quantity
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { EntityManager, FindManyOptions } from "typeorm"
|
|
||||||
import { isDefined, MedusaError } from "medusa-core-utils"
|
|
||||||
import {
|
import {
|
||||||
buildQuery,
|
buildQuery,
|
||||||
CreateReservationItemInput,
|
CreateReservationItemInput,
|
||||||
FilterableReservationItemProps,
|
FilterableReservationItemProps,
|
||||||
FindConfig,
|
FindConfig,
|
||||||
IEventBusService,
|
IEventBusService,
|
||||||
TransactionBaseService,
|
|
||||||
UpdateReservationItemInput,
|
UpdateReservationItemInput,
|
||||||
} from "@medusajs/medusa"
|
} from "@medusajs/medusa"
|
||||||
|
import { SharedContext } from "@medusajs/types"
|
||||||
import { ReservationItem } from "../models"
|
import { InjectEntityManager, MedusaContext } from "@medusajs/utils"
|
||||||
|
import { isDefined, MedusaError } from "medusa-core-utils"
|
||||||
|
import { EntityManager, FindManyOptions } from "typeorm"
|
||||||
import { InventoryLevelService } from "."
|
import { InventoryLevelService } from "."
|
||||||
|
import { ReservationItem } from "../models"
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
eventBusService: IEventBusService
|
eventBusService: IEventBusService
|
||||||
@@ -19,22 +19,23 @@ type InjectedDependencies = {
|
|||||||
inventoryLevelService: InventoryLevelService
|
inventoryLevelService: InventoryLevelService
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ReservationItemService extends TransactionBaseService {
|
export default class ReservationItemService {
|
||||||
static Events = {
|
static Events = {
|
||||||
CREATED: "reservation-item.created",
|
CREATED: "reservation-item.created",
|
||||||
UPDATED: "reservation-item.updated",
|
UPDATED: "reservation-item.updated",
|
||||||
DELETED: "reservation-item.deleted",
|
DELETED: "reservation-item.deleted",
|
||||||
}
|
}
|
||||||
|
|
||||||
protected readonly eventBusService_: IEventBusService
|
protected readonly manager_: EntityManager
|
||||||
|
protected readonly eventBusService_: IEventBusService | undefined
|
||||||
protected readonly inventoryLevelService_: InventoryLevelService
|
protected readonly inventoryLevelService_: InventoryLevelService
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
eventBusService,
|
eventBusService,
|
||||||
inventoryLevelService,
|
inventoryLevelService,
|
||||||
|
manager,
|
||||||
}: InjectedDependencies) {
|
}: InjectedDependencies) {
|
||||||
super(arguments[0])
|
this.manager_ = manager
|
||||||
|
|
||||||
this.eventBusService_ = eventBusService
|
this.eventBusService_ = eventBusService
|
||||||
this.inventoryLevelService_ = inventoryLevelService
|
this.inventoryLevelService_ = inventoryLevelService
|
||||||
}
|
}
|
||||||
@@ -45,11 +46,13 @@ export default class ReservationItemService extends TransactionBaseService {
|
|||||||
* @param config - Configuration for the query.
|
* @param config - Configuration for the query.
|
||||||
* @return Array of reservation items that match the selector.
|
* @return Array of reservation items that match the selector.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async list(
|
async list(
|
||||||
selector: FilterableReservationItemProps = {},
|
selector: FilterableReservationItemProps = {},
|
||||||
config: FindConfig<ReservationItem> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<ReservationItem> = { relations: [], skip: 0, take: 10 },
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<ReservationItem[]> {
|
): Promise<ReservationItem[]> {
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const itemRepository = manager.getRepository(ReservationItem)
|
const itemRepository = manager.getRepository(ReservationItem)
|
||||||
|
|
||||||
const query = buildQuery(selector, config) as FindManyOptions
|
const query = buildQuery(selector, config) as FindManyOptions
|
||||||
@@ -62,11 +65,13 @@ export default class ReservationItemService extends TransactionBaseService {
|
|||||||
* @param config - Configuration for the query.
|
* @param config - Configuration for the query.
|
||||||
* @return Array of reservation items that match the selector and the total count.
|
* @return Array of reservation items that match the selector and the total count.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async listAndCount(
|
async listAndCount(
|
||||||
selector: FilterableReservationItemProps = {},
|
selector: FilterableReservationItemProps = {},
|
||||||
config: FindConfig<ReservationItem> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<ReservationItem> = { relations: [], skip: 0, take: 10 },
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<[ReservationItem[], number]> {
|
): Promise<[ReservationItem[], number]> {
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const itemRepository = manager.getRepository(ReservationItem)
|
const itemRepository = manager.getRepository(ReservationItem)
|
||||||
|
|
||||||
const query = buildQuery(selector, config) as FindManyOptions
|
const query = buildQuery(selector, config) as FindManyOptions
|
||||||
@@ -80,9 +85,11 @@ export default class ReservationItemService extends TransactionBaseService {
|
|||||||
* @return The reservation item with the provided id.
|
* @return The reservation item with the provided id.
|
||||||
* @throws If reservationItemId is not defined or if the reservation item was not found.
|
* @throws If reservationItemId is not defined or if the reservation item was not found.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async retrieve(
|
async retrieve(
|
||||||
reservationItemId: string,
|
reservationItemId: string,
|
||||||
config: FindConfig<ReservationItem> = {}
|
config: FindConfig<ReservationItem> = {},
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<ReservationItem> {
|
): Promise<ReservationItem> {
|
||||||
if (!isDefined(reservationItemId)) {
|
if (!isDefined(reservationItemId)) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -91,7 +98,7 @@ export default class ReservationItemService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = this.activeManager_
|
const manager = context.transactionManager!
|
||||||
const reservationItemRepository = manager.getRepository(ReservationItem)
|
const reservationItemRepository = manager.getRepository(ReservationItem)
|
||||||
|
|
||||||
const query = buildQuery(
|
const query = buildQuery(
|
||||||
@@ -115,37 +122,37 @@ export default class ReservationItemService extends TransactionBaseService {
|
|||||||
* @param data - The reservation item data.
|
* @param data - The reservation item data.
|
||||||
* @return The created reservation item.
|
* @return The created reservation item.
|
||||||
*/
|
*/
|
||||||
async create(data: CreateReservationItemInput): Promise<ReservationItem> {
|
@InjectEntityManager()
|
||||||
return await this.atomicPhase_(async (manager) => {
|
async create(
|
||||||
const itemRepository = manager.getRepository(ReservationItem)
|
data: CreateReservationItemInput,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<ReservationItem> {
|
||||||
|
const manager = context.transactionManager!
|
||||||
|
const itemRepository = manager.getRepository(ReservationItem)
|
||||||
|
|
||||||
const inventoryItem = itemRepository.create({
|
const inventoryItem = itemRepository.create({
|
||||||
inventory_item_id: data.inventory_item_id,
|
inventory_item_id: data.inventory_item_id,
|
||||||
line_item_id: data.line_item_id,
|
line_item_id: data.line_item_id,
|
||||||
location_id: data.location_id,
|
location_id: data.location_id,
|
||||||
quantity: data.quantity,
|
quantity: data.quantity,
|
||||||
metadata: data.metadata,
|
metadata: data.metadata,
|
||||||
})
|
|
||||||
|
|
||||||
const [newInventoryItem] = await Promise.all([
|
|
||||||
itemRepository.save(inventoryItem),
|
|
||||||
this.inventoryLevelService_
|
|
||||||
.withTransaction(manager)
|
|
||||||
.adjustReservedQuantity(
|
|
||||||
data.inventory_item_id,
|
|
||||||
data.location_id,
|
|
||||||
data.quantity
|
|
||||||
),
|
|
||||||
])
|
|
||||||
|
|
||||||
await this.eventBusService_
|
|
||||||
.withTransaction(manager)
|
|
||||||
.emit(ReservationItemService.Events.CREATED, {
|
|
||||||
id: newInventoryItem.id,
|
|
||||||
})
|
|
||||||
|
|
||||||
return newInventoryItem
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [newInventoryItem] = await Promise.all([
|
||||||
|
itemRepository.save(inventoryItem),
|
||||||
|
this.inventoryLevelService_.adjustReservedQuantity(
|
||||||
|
data.inventory_item_id,
|
||||||
|
data.location_id,
|
||||||
|
data.quantity,
|
||||||
|
context
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
|
await this.eventBusService_?.emit?.(ReservationItemService.Events.CREATED, {
|
||||||
|
id: newInventoryItem.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
return newInventoryItem
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -154,99 +161,99 @@ export default class ReservationItemService extends TransactionBaseService {
|
|||||||
* @param data - The reservation item data to update.
|
* @param data - The reservation item data to update.
|
||||||
* @return The updated reservation item.
|
* @return The updated reservation item.
|
||||||
*/
|
*/
|
||||||
|
@InjectEntityManager()
|
||||||
async update(
|
async update(
|
||||||
reservationItemId: string,
|
reservationItemId: string,
|
||||||
data: UpdateReservationItemInput
|
data: UpdateReservationItemInput,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
): Promise<ReservationItem> {
|
): Promise<ReservationItem> {
|
||||||
return await this.atomicPhase_(async (manager) => {
|
const manager = context.transactionManager!
|
||||||
const itemRepository = manager.getRepository(ReservationItem)
|
const itemRepository = manager.getRepository(ReservationItem)
|
||||||
|
|
||||||
const item = await this.retrieve(reservationItemId)
|
const item = await this.retrieve(reservationItemId)
|
||||||
|
|
||||||
const shouldUpdateQuantity =
|
const shouldUpdateQuantity =
|
||||||
isDefined(data.quantity) && data.quantity !== item.quantity
|
isDefined(data.quantity) && data.quantity !== item.quantity
|
||||||
|
|
||||||
const shouldUpdateLocation =
|
const shouldUpdateLocation =
|
||||||
isDefined(data.location_id) && data.location_id !== item.location_id
|
isDefined(data.location_id) && data.location_id !== item.location_id
|
||||||
|
|
||||||
const ops: Promise<unknown>[] = []
|
const ops: Promise<unknown>[] = []
|
||||||
|
|
||||||
if (shouldUpdateLocation) {
|
if (shouldUpdateLocation) {
|
||||||
ops.push(
|
ops.push(
|
||||||
this.inventoryLevelService_
|
this.inventoryLevelService_.adjustReservedQuantity(
|
||||||
.withTransaction(manager)
|
item.inventory_item_id,
|
||||||
.adjustReservedQuantity(
|
item.location_id,
|
||||||
item.inventory_item_id,
|
item.quantity * -1,
|
||||||
item.location_id,
|
context
|
||||||
item.quantity * -1
|
),
|
||||||
),
|
this.inventoryLevelService_.adjustReservedQuantity(
|
||||||
this.inventoryLevelService_
|
item.inventory_item_id,
|
||||||
.withTransaction(manager)
|
data.location_id!,
|
||||||
.adjustReservedQuantity(
|
data.quantity || item.quantity!,
|
||||||
item.inventory_item_id,
|
context
|
||||||
data.location_id!,
|
|
||||||
data.quantity || item.quantity!
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
} else if (shouldUpdateQuantity) {
|
)
|
||||||
const quantityDiff = data.quantity! - item.quantity
|
} else if (shouldUpdateQuantity) {
|
||||||
ops.push(
|
const quantityDiff = data.quantity! - item.quantity
|
||||||
this.inventoryLevelService_
|
ops.push(
|
||||||
.withTransaction(manager)
|
this.inventoryLevelService_.adjustReservedQuantity(
|
||||||
.adjustReservedQuantity(
|
item.inventory_item_id,
|
||||||
item.inventory_item_id,
|
item.location_id,
|
||||||
item.location_id,
|
quantityDiff,
|
||||||
quantityDiff
|
context
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const mergedItem = itemRepository.merge(item, data)
|
const mergedItem = itemRepository.merge(item, data)
|
||||||
|
|
||||||
ops.push(itemRepository.save(item))
|
ops.push(itemRepository.save(item))
|
||||||
|
|
||||||
await Promise.all(ops)
|
await Promise.all(ops)
|
||||||
|
|
||||||
await this.eventBusService_
|
await this.eventBusService_?.emit?.(ReservationItemService.Events.UPDATED, {
|
||||||
.withTransaction(manager)
|
id: mergedItem.id,
|
||||||
.emit(ReservationItemService.Events.UPDATED, {
|
|
||||||
id: mergedItem.id,
|
|
||||||
})
|
|
||||||
|
|
||||||
return mergedItem
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return mergedItem
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a reservation item by line item id.
|
* Deletes a reservation item by line item id.
|
||||||
* @param lineItemId - the id of the line item to delete.
|
* @param lineItemId - the id of the line item to delete.
|
||||||
*/
|
*/
|
||||||
async deleteByLineItem(lineItemId: string): Promise<void> {
|
@InjectEntityManager()
|
||||||
await this.atomicPhase_(async (manager) => {
|
async deleteByLineItem(
|
||||||
const itemRepository = manager.getRepository(ReservationItem)
|
lineItemId: string,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const manager = context.transactionManager!
|
||||||
|
const itemRepository = manager.getRepository(ReservationItem)
|
||||||
|
|
||||||
const items = await this.list({ line_item_id: lineItemId })
|
const items = await this.list(
|
||||||
|
{ line_item_id: lineItemId },
|
||||||
|
undefined,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
const ops: Promise<unknown>[] = []
|
const ops: Promise<unknown>[] = []
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
ops.push(itemRepository.softRemove({ line_item_id: lineItemId }))
|
ops.push(itemRepository.softRemove({ line_item_id: lineItemId }))
|
||||||
ops.push(
|
ops.push(
|
||||||
this.inventoryLevelService_
|
this.inventoryLevelService_.adjustReservedQuantity(
|
||||||
.withTransaction(manager)
|
item.inventory_item_id,
|
||||||
.adjustReservedQuantity(
|
item.location_id,
|
||||||
item.inventory_item_id,
|
item.quantity * -1,
|
||||||
item.location_id,
|
context
|
||||||
item.quantity * -1
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
await Promise.all(ops)
|
}
|
||||||
|
await Promise.all(ops)
|
||||||
|
|
||||||
await this.eventBusService_
|
await this.eventBusService_?.emit?.(ReservationItemService.Events.DELETED, {
|
||||||
.withTransaction(manager)
|
line_item_id: lineItemId,
|
||||||
.emit(ReservationItemService.Events.DELETED, {
|
|
||||||
line_item_id: lineItemId,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,22 +261,23 @@ export default class ReservationItemService extends TransactionBaseService {
|
|||||||
* Deletes reservation items by location ID.
|
* Deletes reservation items by location ID.
|
||||||
* @param locationId - The ID of the location to delete reservations for.
|
* @param locationId - The ID of the location to delete reservations for.
|
||||||
*/
|
*/
|
||||||
async deleteByLocationId(locationId: string): Promise<void> {
|
@InjectEntityManager()
|
||||||
return await this.atomicPhase_(async (manager) => {
|
async deleteByLocationId(
|
||||||
const itemRepository = manager.getRepository(ReservationItem)
|
locationId: string,
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const manager = context.transactionManager!
|
||||||
|
const itemRepository = manager.getRepository(ReservationItem)
|
||||||
|
|
||||||
await itemRepository
|
await itemRepository
|
||||||
.createQueryBuilder("reservation_item")
|
.createQueryBuilder("reservation_item")
|
||||||
.softDelete()
|
.softDelete()
|
||||||
.where("location_id = :locationId", { locationId })
|
.where("location_id = :locationId", { locationId })
|
||||||
.andWhere("deleted_at IS NULL")
|
.andWhere("deleted_at IS NULL")
|
||||||
.execute()
|
.execute()
|
||||||
|
|
||||||
await this.eventBusService_
|
await this.eventBusService_?.emit?.(ReservationItemService.Events.DELETED, {
|
||||||
.withTransaction(manager)
|
location_id: locationId,
|
||||||
.emit(ReservationItemService.Events.DELETED, {
|
|
||||||
location_id: locationId,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,35 +285,32 @@ export default class ReservationItemService extends TransactionBaseService {
|
|||||||
* Deletes a reservation item by id.
|
* Deletes a reservation item by id.
|
||||||
* @param reservationItemId - the id of the reservation item to delete.
|
* @param reservationItemId - the id of the reservation item to delete.
|
||||||
*/
|
*/
|
||||||
async delete(reservationItemId: string | string[]): Promise<void> {
|
async delete(
|
||||||
|
reservationItemId: string | string[],
|
||||||
|
@MedusaContext() context: SharedContext = {}
|
||||||
|
): Promise<void> {
|
||||||
const ids = Array.isArray(reservationItemId)
|
const ids = Array.isArray(reservationItemId)
|
||||||
? reservationItemId
|
? reservationItemId
|
||||||
: [reservationItemId]
|
: [reservationItemId]
|
||||||
return await this.atomicPhase_(async (manager) => {
|
const manager = context.transactionManager!
|
||||||
const itemRepository = manager.getRepository(ReservationItem)
|
const itemRepository = manager.getRepository(ReservationItem)
|
||||||
|
const items = await this.list({ id: ids })
|
||||||
|
|
||||||
const items = await this.list({ id: ids })
|
const promises: Promise<unknown>[] = items.map(async (item) => {
|
||||||
|
this.inventoryLevelService_.adjustReservedQuantity(
|
||||||
await itemRepository.softRemove(items)
|
item.inventory_item_id,
|
||||||
|
item.location_id,
|
||||||
const inventoryServiceTx =
|
item.quantity * -1,
|
||||||
this.inventoryLevelService_.withTransaction(manager)
|
context
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
items.map(async (item) => {
|
|
||||||
return inventoryServiceTx.adjustReservedQuantity(
|
|
||||||
item.inventory_item_id,
|
|
||||||
item.location_id,
|
|
||||||
item.quantity * -1
|
|
||||||
)
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
})
|
||||||
|
|
||||||
await this.eventBusService_
|
promises.push(itemRepository.softRemove(items))
|
||||||
.withTransaction(manager)
|
|
||||||
.emit(ReservationItemService.Events.DELETED, {
|
await Promise.all(promises)
|
||||||
id: reservationItemId,
|
|
||||||
})
|
await this.eventBusService_?.emit?.(ReservationItemService.Events.DELETED, {
|
||||||
|
id: reservationItemId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { DatabaseType } from "typeorm"
|
||||||
|
|
||||||
|
export type InventoryServiceInitializeOptions = {
|
||||||
|
database?: {
|
||||||
|
type?: DatabaseType | string
|
||||||
|
url?: string
|
||||||
|
database?: string
|
||||||
|
extra?: Record<string, any>
|
||||||
|
schema?: string
|
||||||
|
logging?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,9 +85,6 @@ export default async (req, res) => {
|
|||||||
const orderServiceTx = orderService.withTransaction(manager)
|
const orderServiceTx = orderService.withTransaction(manager)
|
||||||
const cartServiceTx = cartService.withTransaction(manager)
|
const cartServiceTx = cartService.withTransaction(manager)
|
||||||
|
|
||||||
const productVariantInventoryServiceTx =
|
|
||||||
productVariantInventoryService.withTransaction(manager)
|
|
||||||
|
|
||||||
const draftOrder = await draftOrderServiceTx.retrieve(id)
|
const draftOrder = await draftOrderServiceTx.retrieve(id)
|
||||||
|
|
||||||
const cart = await cartServiceTx.retrieveWithTotals(draftOrder.cart_id)
|
const cart = await cartServiceTx.retrieveWithTotals(draftOrder.cart_id)
|
||||||
@@ -116,7 +113,7 @@ export default async (req, res) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await reserveQuantityForDraftOrder(order, {
|
await reserveQuantityForDraftOrder(order, {
|
||||||
productVariantInventoryService: productVariantInventoryServiceTx,
|
productVariantInventoryService,
|
||||||
})
|
})
|
||||||
|
|
||||||
return order
|
return order
|
||||||
|
|||||||
@@ -59,9 +59,7 @@ export default async (req: Request, res: Response) => {
|
|||||||
.withTransaction(transactionManager)
|
.withTransaction(transactionManager)
|
||||||
.detachInventoryItem(id)
|
.detachInventoryItem(id)
|
||||||
|
|
||||||
await inventoryService
|
await inventoryService.deleteInventoryItem(id)
|
||||||
.withTransaction(transactionManager)
|
|
||||||
.deleteInventoryItem(id)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
res.status(200).send({
|
res.status(200).send({
|
||||||
|
|||||||
@@ -74,11 +74,7 @@ export default async (req: Request, res: Response) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
await manager.transaction(async (transactionManager) => {
|
await inventoryService.deleteInventoryLevel(id, location_id)
|
||||||
await inventoryService
|
|
||||||
.withTransaction(transactionManager)
|
|
||||||
.deleteInventoryLevel(id, location_id)
|
|
||||||
})
|
|
||||||
|
|
||||||
const inventoryItem = await inventoryService.retrieveInventoryItem(
|
const inventoryItem = await inventoryService.retrieveInventoryItem(
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -77,14 +77,10 @@ export default async (req: Request, res: Response) => {
|
|||||||
req.scope.resolve("inventoryService")
|
req.scope.resolve("inventoryService")
|
||||||
const manager: EntityManager = req.scope.resolve("manager")
|
const manager: EntityManager = req.scope.resolve("manager")
|
||||||
|
|
||||||
await manager.transaction(async (transactionManager) => {
|
await inventoryService.updateInventoryItem(
|
||||||
await inventoryService
|
id,
|
||||||
.withTransaction(transactionManager)
|
req.validatedBody as AdminPostInventoryItemsInventoryItemReq
|
||||||
.updateInventoryItem(
|
)
|
||||||
id,
|
|
||||||
req.validatedBody as AdminPostInventoryItemsInventoryItemReq
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const inventoryItem = await inventoryService.retrieveInventoryItem(
|
const inventoryItem = await inventoryService.retrieveInventoryItem(
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -81,11 +81,7 @@ export default async (req: Request, res: Response) => {
|
|||||||
const validatedBody =
|
const validatedBody =
|
||||||
req.validatedBody as AdminPostInventoryItemsItemLocationLevelsLevelReq
|
req.validatedBody as AdminPostInventoryItemsItemLocationLevelsLevelReq
|
||||||
|
|
||||||
await manager.transaction(async (transactionManager) => {
|
await inventoryService.updateInventoryLevel(id, location_id, validatedBody)
|
||||||
await inventoryService
|
|
||||||
.withTransaction(transactionManager)
|
|
||||||
.updateInventoryLevel(id, location_id, validatedBody)
|
|
||||||
})
|
|
||||||
|
|
||||||
const inventoryItem = await inventoryService.retrieveInventoryItem(
|
const inventoryItem = await inventoryService.retrieveInventoryItem(
|
||||||
id,
|
id,
|
||||||
|
|||||||
+11
-11
@@ -1,3 +1,14 @@
|
|||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
import { EntityManager } from "typeorm"
|
||||||
|
import { ulid } from "ulid"
|
||||||
|
import { IInventoryService } from "../../../../../interfaces"
|
||||||
|
import { ProductVariant } from "../../../../../models"
|
||||||
|
import {
|
||||||
|
ProductVariantInventoryService,
|
||||||
|
ProductVariantService,
|
||||||
|
} from "../../../../../services"
|
||||||
|
import { InventoryItemDTO } from "../../../../../types/inventory"
|
||||||
|
import { CreateProductVariantInput } from "../../../../../types/product-variant"
|
||||||
import {
|
import {
|
||||||
DistributedTransaction,
|
DistributedTransaction,
|
||||||
TransactionHandlerType,
|
TransactionHandlerType,
|
||||||
@@ -6,17 +17,6 @@ import {
|
|||||||
TransactionState,
|
TransactionState,
|
||||||
TransactionStepsDefinition,
|
TransactionStepsDefinition,
|
||||||
} from "../../../../../utils/transaction"
|
} from "../../../../../utils/transaction"
|
||||||
import { ulid } from "ulid"
|
|
||||||
import { EntityManager } from "typeorm"
|
|
||||||
import { IInventoryService } from "../../../../../interfaces"
|
|
||||||
import {
|
|
||||||
ProductVariantInventoryService,
|
|
||||||
ProductVariantService,
|
|
||||||
} from "../../../../../services"
|
|
||||||
import { CreateProductVariantInput } from "../../../../../types/product-variant"
|
|
||||||
import { InventoryItemDTO } from "../../../../../types/inventory"
|
|
||||||
import { ProductVariant } from "../../../../../models"
|
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
|
|
||||||
enum actions {
|
enum actions {
|
||||||
createVariant = "createVariant",
|
createVariant = "createVariant",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { IsNumber, IsObject, IsOptional, IsString } from "class-validator"
|
import { IsNumber, IsObject, IsOptional, IsString } from "class-validator"
|
||||||
import { isDefined } from "medusa-core-utils"
|
import { isDefined } from "medusa-core-utils"
|
||||||
import { EntityManager } from "typeorm"
|
|
||||||
import { IInventoryService } from "../../../../interfaces"
|
import { IInventoryService } from "../../../../interfaces"
|
||||||
import { validateUpdateReservationQuantity } from "./utils/validate-reservation-quantity"
|
import { validateUpdateReservationQuantity } from "./utils/validate-reservation-quantity"
|
||||||
|
|
||||||
@@ -66,8 +65,6 @@ import { validateUpdateReservationQuantity } from "./utils/validate-reservation-
|
|||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const { validatedBody } = req as { validatedBody: AdminPostReservationsReq }
|
const { validatedBody } = req as { validatedBody: AdminPostReservationsReq }
|
||||||
|
|
||||||
const manager: EntityManager = req.scope.resolve("manager")
|
|
||||||
|
|
||||||
const inventoryService: IInventoryService =
|
const inventoryService: IInventoryService =
|
||||||
req.scope.resolve("inventoryService")
|
req.scope.resolve("inventoryService")
|
||||||
|
|
||||||
@@ -82,11 +79,9 @@ export default async (req, res) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const reservation = await manager.transaction(async (manager) => {
|
const reservation = await inventoryService.createReservationItem(
|
||||||
return await inventoryService
|
validatedBody
|
||||||
.withTransaction(manager)
|
)
|
||||||
.createReservationItem(validatedBody)
|
|
||||||
})
|
|
||||||
|
|
||||||
res.status(200).json({ reservation })
|
res.status(200).json({ reservation })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,9 +58,7 @@ export default async (req, res) => {
|
|||||||
req.scope.resolve("inventoryService")
|
req.scope.resolve("inventoryService")
|
||||||
const manager: EntityManager = req.scope.resolve("manager")
|
const manager: EntityManager = req.scope.resolve("manager")
|
||||||
|
|
||||||
await manager.transaction(async (manager) => {
|
await inventoryService.deleteReservationItem(id)
|
||||||
await inventoryService.withTransaction(manager).deleteReservationItem(id)
|
|
||||||
})
|
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -91,9 +91,7 @@ export default async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await manager.transaction(async (manager) => {
|
const result = await manager.transaction(async (manager) => {
|
||||||
await inventoryService
|
await inventoryService.updateReservationItem(id, validatedBody)
|
||||||
.withTransaction(manager)
|
|
||||||
.updateReservationItem(id, validatedBody)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
res.status(200).json({ reservation: result })
|
res.status(200).json({ reservation: result })
|
||||||
|
|||||||
@@ -79,12 +79,8 @@ export default async (req, res) => {
|
|||||||
|
|
||||||
if (inventoryService) {
|
if (inventoryService) {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
inventoryService
|
inventoryService.deleteInventoryItemLevelByLocationId(id),
|
||||||
.withTransaction(transactionManager)
|
inventoryService.deleteReservationItemByLocationId(id),
|
||||||
.deleteInventoryItemLevelByLocationId(id),
|
|
||||||
inventoryService
|
|
||||||
.withTransaction(transactionManager)
|
|
||||||
.deleteReservationItemByLocationId(id),
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ import featureFlagLoader from "../loaders/feature-flags"
|
|||||||
import Logger from "../loaders/logger"
|
import Logger from "../loaders/logger"
|
||||||
import databaseLoader from "../loaders/database"
|
import databaseLoader from "../loaders/database"
|
||||||
import configModuleLoader from "../loaders/config"
|
import configModuleLoader from "../loaders/config"
|
||||||
import getMigrations, { getModuleSharedResources } from "./utils/get-migrations"
|
import getMigrations, {
|
||||||
|
getModuleSharedResources,
|
||||||
|
revertIsolatedModulesMigration,
|
||||||
|
runIsolatedModulesMigration,
|
||||||
|
} from "./utils/get-migrations"
|
||||||
|
|
||||||
const getDataSource = async (directory) => {
|
const getDataSource = async (directory) => {
|
||||||
const configModule = configModuleLoader(directory)
|
const configModule = configModuleLoader(directory)
|
||||||
@@ -34,16 +38,19 @@ const main = async function ({ directory }) {
|
|||||||
args.shift()
|
args.shift()
|
||||||
args.shift()
|
args.shift()
|
||||||
|
|
||||||
|
const configModule = configModuleLoader(directory)
|
||||||
const dataSource = await getDataSource(directory)
|
const dataSource = await getDataSource(directory)
|
||||||
|
|
||||||
if (args[0] === "run") {
|
if (args[0] === "run") {
|
||||||
await dataSource.runMigrations()
|
await dataSource.runMigrations()
|
||||||
await dataSource.destroy()
|
await dataSource.destroy()
|
||||||
|
await runIsolatedModulesMigration(configModule)
|
||||||
Logger.info("Migrations completed.")
|
Logger.info("Migrations completed.")
|
||||||
process.exit()
|
process.exit()
|
||||||
} else if (args[0] === "revert") {
|
} else if (args[0] === "revert") {
|
||||||
await dataSource.undoLastMigration({ transaction: "all" })
|
await dataSource.undoLastMigration({ transaction: "all" })
|
||||||
await dataSource.destroy()
|
await dataSource.destroy()
|
||||||
|
await revertIsolatedModulesMigration(configModule)
|
||||||
Logger.info("Migrations reverted.")
|
Logger.info("Migrations reverted.")
|
||||||
process.exit()
|
process.exit()
|
||||||
} else if (args[0] === "show") {
|
} else if (args[0] === "show") {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { sync as existsSync } from "fs-exists-cached"
|
|||||||
import { getConfigFile } from "medusa-core-utils"
|
import { getConfigFile } from "medusa-core-utils"
|
||||||
import { track } from "medusa-telemetry"
|
import { track } from "medusa-telemetry"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { ConnectionOptions, createConnection } from "typeorm"
|
import { DataSource, DataSourceOptions } from "typeorm"
|
||||||
|
|
||||||
import loaders from "../loaders"
|
import loaders from "../loaders"
|
||||||
import { handleConfigError } from "../loaders/config"
|
import { handleConfigError } from "../loaders/config"
|
||||||
@@ -73,12 +73,14 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) {
|
|||||||
extra: configModule.projectConfig.database_extra || {},
|
extra: configModule.projectConfig.database_extra || {},
|
||||||
migrations: coreMigrations.concat(moduleMigrations),
|
migrations: coreMigrations.concat(moduleMigrations),
|
||||||
logging: true,
|
logging: true,
|
||||||
} as ConnectionOptions
|
} as DataSourceOptions
|
||||||
|
|
||||||
const connection = await createConnection(connectionOptions)
|
const connection = new DataSource(connectionOptions)
|
||||||
|
|
||||||
|
await connection.initialize()
|
||||||
await connection.runMigrations()
|
await connection.runMigrations()
|
||||||
await connection.close()
|
await connection.destroy()
|
||||||
|
|
||||||
Logger.info("Migrations completed.")
|
Logger.info("Migrations completed.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { registerModules } from "@medusajs/modules-sdk"
|
import { MedusaModule, registerModules } from "@medusajs/modules-sdk"
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import { sync as existsSync } from "fs-exists-cached"
|
import { sync as existsSync } from "fs-exists-cached"
|
||||||
import glob from "glob"
|
import glob from "glob"
|
||||||
@@ -96,7 +96,7 @@ function resolvePlugin(pluginName) {
|
|||||||
export function getInternalModules(configModule) {
|
export function getInternalModules(configModule) {
|
||||||
const modules = []
|
const modules = []
|
||||||
|
|
||||||
const moduleResolutions = registerModules(configModule)
|
const moduleResolutions = registerModules(configModule.modules)
|
||||||
|
|
||||||
for (const moduleResolution of Object.values(moduleResolutions)) {
|
for (const moduleResolution of Object.values(moduleResolutions)) {
|
||||||
if (
|
if (
|
||||||
@@ -200,7 +200,6 @@ export const getModuleMigrations = (configModule, isFlagEnabled) => {
|
|||||||
for (const loadedModule of loadedModules) {
|
for (const loadedModule of loadedModules) {
|
||||||
const mod = loadedModule.loadedModule
|
const mod = loadedModule.loadedModule
|
||||||
|
|
||||||
const isolatedMigrations = {}
|
|
||||||
const moduleMigrations = (mod.migrations ?? [])
|
const moduleMigrations = (mod.migrations ?? [])
|
||||||
.map((migration) => {
|
.map((migration) => {
|
||||||
if (
|
if (
|
||||||
@@ -218,7 +217,6 @@ export const getModuleMigrations = (configModule, isFlagEnabled) => {
|
|||||||
moduleDeclaration: loadedModule.moduleDeclaration,
|
moduleDeclaration: loadedModule.moduleDeclaration,
|
||||||
models: mod.models ?? [],
|
models: mod.models ?? [],
|
||||||
migrations: moduleMigrations,
|
migrations: moduleMigrations,
|
||||||
externalMigrations: isolatedMigrations,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,3 +247,43 @@ export const getModuleSharedResources = (configModule, featureFlagsRouter) => {
|
|||||||
migrations,
|
migrations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const runIsolatedModulesMigration = async (configModule) => {
|
||||||
|
const moduleResolutions = registerModules(configModule.modules)
|
||||||
|
|
||||||
|
for (const moduleResolution of Object.values(moduleResolutions)) {
|
||||||
|
if (
|
||||||
|
!moduleResolution.resolutionPath ||
|
||||||
|
moduleResolution.moduleDeclaration.scope !== "internal" ||
|
||||||
|
moduleResolution.moduleDeclaration.resources !== "isolated"
|
||||||
|
) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
await MedusaModule.migrateUp(
|
||||||
|
moduleResolution.definition.key,
|
||||||
|
moduleResolution.resolutionPath,
|
||||||
|
moduleResolution.options
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const revertIsolatedModulesMigration = async (configModule) => {
|
||||||
|
const moduleResolutions = registerModules(configModule.modules)
|
||||||
|
|
||||||
|
for (const moduleResolution of Object.values(moduleResolutions)) {
|
||||||
|
if (
|
||||||
|
!moduleResolution.resolutionPath ||
|
||||||
|
moduleResolution.moduleDeclaration.scope !== "internal" ||
|
||||||
|
moduleResolution.moduleDeclaration.resources !== "isolated"
|
||||||
|
) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
await MedusaModule.migrateDown(
|
||||||
|
moduleResolution.definition.key,
|
||||||
|
moduleResolution.resolutionPath,
|
||||||
|
moduleResolution.options
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { EntityManager } from "typeorm"
|
|
||||||
import { FindConfig } from "../../types/common"
|
import { FindConfig } from "../../types/common"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -16,8 +15,6 @@ import {
|
|||||||
} from "../../types/inventory"
|
} from "../../types/inventory"
|
||||||
|
|
||||||
export interface IInventoryService {
|
export interface IInventoryService {
|
||||||
withTransaction(transactionManager?: EntityManager): this
|
|
||||||
|
|
||||||
listInventoryItems(
|
listInventoryItems(
|
||||||
selector: FilterableInventoryItemProps,
|
selector: FilterableInventoryItemProps,
|
||||||
config?: FindConfig<InventoryItemDTO>
|
config?: FindConfig<InventoryItemDTO>
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export default async ({
|
|||||||
track("MODULES_INIT_STARTED")
|
track("MODULES_INIT_STARTED")
|
||||||
await moduleLoader({
|
await moduleLoader({
|
||||||
container,
|
container,
|
||||||
moduleResolutions: registerModules(configModule),
|
moduleResolutions: registerModules(configModule?.modules),
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
})
|
})
|
||||||
const modAct = Logger.success(modulesActivity, "Modules initialized") || {}
|
const modAct = Logger.success(modulesActivity, "Modules initialized") || {}
|
||||||
|
|||||||
@@ -24,11 +24,18 @@ describe("EventBusService", () => {
|
|||||||
find: () => Promise.resolve([]),
|
find: () => Promise.resolve([]),
|
||||||
})
|
})
|
||||||
|
|
||||||
eventBus = new EventBusService({
|
eventBus = new EventBusService(
|
||||||
manager: MockManager,
|
{
|
||||||
stagedJobRepository,
|
manager: MockManager,
|
||||||
logger: loggerMock,
|
stagedJobRepository,
|
||||||
})
|
logger: loggerMock,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
projectConfig: {
|
||||||
|
redis_url: "localhost",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@@ -49,10 +56,17 @@ describe("EventBusService", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetAllMocks()
|
jest.resetAllMocks()
|
||||||
|
|
||||||
eventBus = new EventBusService({
|
eventBus = new EventBusService(
|
||||||
manager: MockManager,
|
{
|
||||||
logger: loggerMock,
|
manager: MockManager,
|
||||||
})
|
logger: loggerMock,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
projectConfig: {
|
||||||
|
redis_url: "localhost",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@@ -135,11 +149,18 @@ describe("EventBusService", () => {
|
|||||||
create: (data) => data,
|
create: (data) => data,
|
||||||
})
|
})
|
||||||
|
|
||||||
eventBus = new EventBusService({
|
eventBus = new EventBusService(
|
||||||
logger: loggerMock,
|
{
|
||||||
manager: mockManager,
|
logger: loggerMock,
|
||||||
stagedJobRepository,
|
manager: mockManager,
|
||||||
})
|
stagedJobRepository,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
projectConfig: {
|
||||||
|
redis_url: "localhost",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
eventBus.queue_.addBulk.mockImplementationOnce(() => "hi")
|
eventBus.queue_.addBulk.mockImplementationOnce(() => "hi")
|
||||||
})
|
})
|
||||||
@@ -195,11 +216,18 @@ describe("EventBusService", () => {
|
|||||||
create: (data) => data,
|
create: (data) => data,
|
||||||
})
|
})
|
||||||
|
|
||||||
eventBus = new EventBusService({
|
eventBus = new EventBusService(
|
||||||
logger: loggerMock,
|
{
|
||||||
manager: mockManager,
|
logger: loggerMock,
|
||||||
stagedJobRepository,
|
manager: mockManager,
|
||||||
})
|
stagedJobRepository,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
projectConfig: {
|
||||||
|
redis_url: "localhost",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
eventBus.queue_.addBulk.mockImplementationOnce(() => "hi")
|
eventBus.queue_.addBulk.mockImplementationOnce(() => "hi")
|
||||||
})
|
})
|
||||||
@@ -285,7 +313,10 @@ describe("EventBusService", () => {
|
|||||||
stagedJobRepository,
|
stagedJobRepository,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
projectConfig: { event_options: { removeOnComplete: 10 } },
|
projectConfig: {
|
||||||
|
event_options: { removeOnComplete: 10 },
|
||||||
|
redis_url: "localhost",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -323,11 +354,18 @@ describe("EventBusService", () => {
|
|||||||
create: (data) => data,
|
create: (data) => data,
|
||||||
})
|
})
|
||||||
|
|
||||||
eventBus = new EventBusService({
|
eventBus = new EventBusService(
|
||||||
logger: loggerMock,
|
{
|
||||||
manager: mockManager,
|
logger: loggerMock,
|
||||||
stagedJobRepository,
|
manager: mockManager,
|
||||||
})
|
stagedJobRepository,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
projectConfig: {
|
||||||
|
redis_url: "localhost",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
eventBus.queue_.addBulk.mockImplementationOnce(() => "hi")
|
eventBus.queue_.addBulk.mockImplementationOnce(() => "hi")
|
||||||
|
|
||||||
@@ -370,7 +408,10 @@ describe("EventBusService", () => {
|
|||||||
stagedJobRepository,
|
stagedJobRepository,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
projectConfig: { event_options: { removeOnComplete: 10 } },
|
projectConfig: {
|
||||||
|
event_options: { removeOnComplete: 10 },
|
||||||
|
redis_url: "localhost",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -418,14 +459,11 @@ describe("EventBusService", () => {
|
|||||||
find: () => Promise.resolve([]),
|
find: () => Promise.resolve([]),
|
||||||
})
|
})
|
||||||
|
|
||||||
eventBus = new EventBusService(
|
eventBus = new EventBusService({
|
||||||
{
|
manager: MockManager,
|
||||||
manager: MockManager,
|
stagedJobRepository,
|
||||||
stagedJobRepository,
|
logger: loggerMock,
|
||||||
logger: loggerMock,
|
})
|
||||||
},
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
eventBus.subscribe("eventName", () => Promise.resolve("hi"))
|
eventBus.subscribe("eventName", () => Promise.resolve("hi"))
|
||||||
result = await eventBus.worker_({
|
result = await eventBus.worker_({
|
||||||
data: { eventName: "eventName", data: {} },
|
data: { eventName: "eventName", data: {} },
|
||||||
|
|||||||
@@ -308,7 +308,9 @@ export default class EventBusService {
|
|||||||
return (!isBulkEmit ? stagedJobs[0] : stagedJobs) as unknown as TResult
|
return (!isBulkEmit ? stagedJobs[0] : stagedJobs) as unknown as TResult
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.queue_.addBulk(events)
|
if (this.config_?.projectConfig?.redis_url) {
|
||||||
|
await this.queue_.addBulk(events)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
startEnqueuer(): void {
|
startEnqueuer(): void {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { isDefined, MedusaError } from "medusa-core-utils"
|
||||||
import {
|
import {
|
||||||
Brackets,
|
Brackets,
|
||||||
EntityManager,
|
EntityManager,
|
||||||
@@ -9,37 +10,36 @@ import {
|
|||||||
IsNull,
|
IsNull,
|
||||||
SelectQueryBuilder,
|
SelectQueryBuilder,
|
||||||
} from "typeorm"
|
} from "typeorm"
|
||||||
import {
|
|
||||||
CreateProductVariantInput,
|
|
||||||
FilterableProductVariantProps,
|
|
||||||
GetRegionPriceContext,
|
|
||||||
ProductVariantPrice,
|
|
||||||
UpdateProductVariantInput,
|
|
||||||
} from "../types/product-variant"
|
|
||||||
import {
|
|
||||||
FindWithRelationsOptions,
|
|
||||||
ProductVariantRepository,
|
|
||||||
} from "../repositories/product-variant"
|
|
||||||
import {
|
import {
|
||||||
IPriceSelectionStrategy,
|
IPriceSelectionStrategy,
|
||||||
PriceSelectionContext,
|
PriceSelectionContext,
|
||||||
TransactionBaseService,
|
TransactionBaseService,
|
||||||
} from "../interfaces"
|
} from "../interfaces"
|
||||||
import { MedusaError, isDefined } from "medusa-core-utils"
|
|
||||||
import {
|
import {
|
||||||
MoneyAmount,
|
MoneyAmount,
|
||||||
Product,
|
Product,
|
||||||
ProductOptionValue,
|
ProductOptionValue,
|
||||||
ProductVariant,
|
ProductVariant,
|
||||||
} from "../models"
|
} from "../models"
|
||||||
|
import {
|
||||||
|
FindWithRelationsOptions,
|
||||||
|
ProductVariantRepository,
|
||||||
|
} from "../repositories/product-variant"
|
||||||
|
import {
|
||||||
|
CreateProductVariantInput,
|
||||||
|
FilterableProductVariantProps,
|
||||||
|
GetRegionPriceContext,
|
||||||
|
ProductVariantPrice,
|
||||||
|
UpdateProductVariantInput,
|
||||||
|
} from "../types/product-variant"
|
||||||
import { buildQuery, buildRelations, setMetadata } from "../utils"
|
import { buildQuery, buildRelations, setMetadata } from "../utils"
|
||||||
|
|
||||||
import { CartRepository } from "../repositories/cart"
|
import { CartRepository } from "../repositories/cart"
|
||||||
import EventBusService from "./event-bus"
|
|
||||||
import { FindConfig } from "../types/common"
|
|
||||||
import { MoneyAmountRepository } from "../repositories/money-amount"
|
import { MoneyAmountRepository } from "../repositories/money-amount"
|
||||||
import { ProductOptionValueRepository } from "../repositories/product-option-value"
|
|
||||||
import { ProductRepository } from "../repositories/product"
|
import { ProductRepository } from "../repositories/product"
|
||||||
|
import { ProductOptionValueRepository } from "../repositories/product-option-value"
|
||||||
|
import { FindConfig } from "../types/common"
|
||||||
|
import EventBusService from "./event-bus"
|
||||||
import RegionService from "./region"
|
import RegionService from "./region"
|
||||||
|
|
||||||
class ProductVariantService extends TransactionBaseService {
|
class ProductVariantService extends TransactionBaseService {
|
||||||
@@ -173,7 +173,9 @@ class ProductVariantService extends TransactionBaseService {
|
|||||||
"options",
|
"options",
|
||||||
]),
|
]),
|
||||||
})) as Product
|
})) as Product
|
||||||
} else if (!product.id) {
|
}
|
||||||
|
|
||||||
|
if (!product?.id) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
`Product id missing`
|
`Product id missing`
|
||||||
|
|||||||
@@ -42,9 +42,10 @@ class SalesChannelInventoryService extends TransactionBaseService {
|
|||||||
.withTransaction(this.activeManager_)
|
.withTransaction(this.activeManager_)
|
||||||
.listLocationIds(salesChannelId)
|
.listLocationIds(salesChannelId)
|
||||||
|
|
||||||
return await this.inventoryService_
|
return await this.inventoryService_.retrieveAvailableQuantity(
|
||||||
.withTransaction(this.activeManager_)
|
inventoryItemId,
|
||||||
.retrieveAvailableQuantity(inventoryItemId, locationIds)
|
locationIds
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ type InjectedDependencies = {
|
|||||||
|
|
||||||
class SalesChannelLocationService extends TransactionBaseService {
|
class SalesChannelLocationService extends TransactionBaseService {
|
||||||
protected readonly salesChannelService_: SalesChannelService
|
protected readonly salesChannelService_: SalesChannelService
|
||||||
protected readonly eventBusService: EventBusService
|
protected readonly eventBusService_: EventBusService
|
||||||
protected readonly stockLocationService: IStockLocationService
|
protected readonly stockLocationService_: IStockLocationService
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
salesChannelService,
|
salesChannelService,
|
||||||
@@ -30,8 +30,8 @@ class SalesChannelLocationService extends TransactionBaseService {
|
|||||||
super(arguments[0])
|
super(arguments[0])
|
||||||
|
|
||||||
this.salesChannelService_ = salesChannelService
|
this.salesChannelService_ = salesChannelService
|
||||||
this.eventBusService = eventBusService
|
this.eventBusService_ = eventBusService
|
||||||
this.stockLocationService = stockLocationService
|
this.stockLocationService_ = stockLocationService
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,9 +77,9 @@ class SalesChannelLocationService extends TransactionBaseService {
|
|||||||
.withTransaction(this.activeManager_)
|
.withTransaction(this.activeManager_)
|
||||||
.retrieve(salesChannelId)
|
.retrieve(salesChannelId)
|
||||||
|
|
||||||
if (this.stockLocationService) {
|
if (this.stockLocationService_) {
|
||||||
// trhows error if not found
|
// trhows error if not found
|
||||||
await this.stockLocationService.retrieve(locationId)
|
await this.stockLocationService_.retrieve(locationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
const salesChannelLocation = this.activeManager_.create(
|
const salesChannelLocation = this.activeManager_.create(
|
||||||
@@ -129,7 +129,7 @@ class SalesChannelLocationService extends TransactionBaseService {
|
|||||||
*/
|
*/
|
||||||
async listSalesChannelIds(locationId: string): Promise<string[]> {
|
async listSalesChannelIds(locationId: string): Promise<string[]> {
|
||||||
const manager = this.transactionManager_ || this.manager_
|
const manager = this.transactionManager_ || this.manager_
|
||||||
const location = await this.stockLocationService.retrieve(locationId)
|
const location = await this.stockLocationService_.retrieve(locationId)
|
||||||
|
|
||||||
const salesChannelLocations = await manager.find(SalesChannelLocation, {
|
const salesChannelLocations = await manager.find(SalesChannelLocation, {
|
||||||
where: { location_id: location.id },
|
where: { location_id: location.id },
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { InternalModuleDeclaration } from "@medusajs/modules-sdk"
|
import {
|
||||||
import { MedusaContainer as coreMedusaContainer } from "medusa-core-utils"
|
ExternalModuleDeclaration,
|
||||||
|
InternalModuleDeclaration,
|
||||||
|
} from "@medusajs/modules-sdk"
|
||||||
import { Request } from "express"
|
import { Request } from "express"
|
||||||
|
import { MedusaContainer as coreMedusaContainer } from "medusa-core-utils"
|
||||||
import { LoggerOptions } from "typeorm"
|
import { LoggerOptions } from "typeorm"
|
||||||
import { Logger as _Logger } from "winston"
|
import { Logger as _Logger } from "winston"
|
||||||
import { Customer, User } from "../models"
|
import { Customer, User } from "../models"
|
||||||
@@ -91,7 +94,12 @@ export type ConfigModule = {
|
|||||||
admin_cors?: string
|
admin_cors?: string
|
||||||
}
|
}
|
||||||
featureFlags: Record<string, boolean | string>
|
featureFlags: Record<string, boolean | string>
|
||||||
modules?: Record<string, false | string | Partial<InternalModuleDeclaration>>
|
modules?: Record<
|
||||||
|
string,
|
||||||
|
| false
|
||||||
|
| string
|
||||||
|
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
|
||||||
|
>
|
||||||
plugins: (
|
plugins: (
|
||||||
| {
|
| {
|
||||||
resolve: string
|
resolve: string
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from "./definitions"
|
export * from "./definitions"
|
||||||
export * from "./loaders"
|
export * from "./loaders"
|
||||||
|
export * from "./medusa-module"
|
||||||
export * from "./module-helper"
|
export * from "./module-helper"
|
||||||
export * from "./types"
|
export * from "./types"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { EOL } from "os"
|
|
||||||
import { AwilixContainer, ClassOrFunctionReturning, Resolver } from "awilix"
|
import { AwilixContainer, ClassOrFunctionReturning, Resolver } from "awilix"
|
||||||
import { createMedusaContainer } from "medusa-core-utils"
|
import { createMedusaContainer } from "medusa-core-utils"
|
||||||
|
import { EOL } from "os"
|
||||||
import {
|
import {
|
||||||
ModuleResolution,
|
ModuleResolution,
|
||||||
MODULE_RESOURCE_TYPE,
|
MODULE_RESOURCE_TYPE,
|
||||||
@@ -155,7 +155,7 @@ describe("modules loader", () => {
|
|||||||
await moduleLoader({ container, moduleResolutions, logger })
|
await moduleLoader({ container, moduleResolutions, logger })
|
||||||
|
|
||||||
expect(logger.warn).toHaveBeenCalledWith(
|
expect(logger.warn).toHaveBeenCalledWith(
|
||||||
`Could not resolve module: TestService. Error: No service found in module. Make sure your module exports at least one service.${EOL}`
|
`Could not resolve module: TestService. Error: No service found in module. Make sure your module exports a service.${EOL}`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ describe("modules loader", () => {
|
|||||||
await moduleLoader({ container, moduleResolutions, logger })
|
await moduleLoader({ container, moduleResolutions, logger })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
expect(err.message).toEqual(
|
expect(err.message).toEqual(
|
||||||
"No service found in module. Make sure your module exports at least one service."
|
"No service found in module. Make sure your module exports a service."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import MODULE_DEFINITIONS from "../../definitions"
|
||||||
import {
|
import {
|
||||||
InternalModuleDeclaration,
|
InternalModuleDeclaration,
|
||||||
ModuleDefinition,
|
ModuleDefinition,
|
||||||
@@ -5,7 +6,6 @@ import {
|
|||||||
MODULE_SCOPE,
|
MODULE_SCOPE,
|
||||||
} from "../../types"
|
} from "../../types"
|
||||||
import { registerModules } from "../register-modules"
|
import { registerModules } from "../register-modules"
|
||||||
import MODULE_DEFINITIONS from "../../definitions"
|
|
||||||
|
|
||||||
const RESOLVED_PACKAGE = "@medusajs/test-service-resolved"
|
const RESOLVED_PACKAGE = "@medusajs/test-service-resolved"
|
||||||
jest.mock("resolve-cwd", () => jest.fn(() => RESOLVED_PACKAGE))
|
jest.mock("resolve-cwd", () => jest.fn(() => RESOLVED_PACKAGE))
|
||||||
@@ -35,7 +35,7 @@ describe("module definitions loader", () => {
|
|||||||
it("Resolves module with default definition given empty config", () => {
|
it("Resolves module with default definition given empty config", () => {
|
||||||
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
||||||
|
|
||||||
const res = registerModules({ modules: {} })
|
const res = registerModules({})
|
||||||
|
|
||||||
expect(res[defaultDefinition.key]).toEqual(
|
expect(res[defaultDefinition.key]).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -54,9 +54,7 @@ describe("module definitions loader", () => {
|
|||||||
it("Resolves module with no resolution path when given false", () => {
|
it("Resolves module with no resolution path when given false", () => {
|
||||||
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
||||||
|
|
||||||
const res = registerModules({
|
const res = registerModules({ [defaultDefinition.key]: false })
|
||||||
modules: { [defaultDefinition.key]: false },
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(res[defaultDefinition.key]).toEqual(
|
expect(res[defaultDefinition.key]).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -72,9 +70,7 @@ describe("module definitions loader", () => {
|
|||||||
MODULE_DEFINITIONS.push({ ...defaultDefinition, isRequired: true })
|
MODULE_DEFINITIONS.push({ ...defaultDefinition, isRequired: true })
|
||||||
|
|
||||||
try {
|
try {
|
||||||
registerModules({
|
registerModules({ [defaultDefinition.key]: false })
|
||||||
modules: { [defaultDefinition.key]: false },
|
|
||||||
})
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
expect(err.message).toEqual(
|
expect(err.message).toEqual(
|
||||||
`Module: ${defaultDefinition.label} is required`
|
`Module: ${defaultDefinition.label} is required`
|
||||||
@@ -90,9 +86,7 @@ describe("module definitions loader", () => {
|
|||||||
|
|
||||||
MODULE_DEFINITIONS.push(definition)
|
MODULE_DEFINITIONS.push(definition)
|
||||||
|
|
||||||
const res = registerModules({
|
const res = registerModules({})
|
||||||
modules: {},
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(res[defaultDefinition.key]).toEqual(
|
expect(res[defaultDefinition.key]).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -113,9 +107,7 @@ describe("module definitions loader", () => {
|
|||||||
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
||||||
|
|
||||||
const res = registerModules({
|
const res = registerModules({
|
||||||
modules: {
|
[defaultDefinition.key]: defaultDefinition.defaultPackage,
|
||||||
[defaultDefinition.key]: defaultDefinition.defaultPackage,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(res[defaultDefinition.key]).toEqual(
|
expect(res[defaultDefinition.key]).toEqual(
|
||||||
@@ -137,13 +129,11 @@ describe("module definitions loader", () => {
|
|||||||
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
||||||
|
|
||||||
const res = registerModules({
|
const res = registerModules({
|
||||||
modules: {
|
[defaultDefinition.key]: {
|
||||||
[defaultDefinition.key]: {
|
scope: MODULE_SCOPE.INTERNAL,
|
||||||
scope: MODULE_SCOPE.INTERNAL,
|
resolve: defaultDefinition.defaultPackage,
|
||||||
resolve: defaultDefinition.defaultPackage,
|
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
||||||
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
} as InternalModuleDeclaration,
|
||||||
} as InternalModuleDeclaration,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(res[defaultDefinition.key]).toEqual(
|
expect(res[defaultDefinition.key]).toEqual(
|
||||||
@@ -164,10 +154,8 @@ describe("module definitions loader", () => {
|
|||||||
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
||||||
|
|
||||||
const res = registerModules({
|
const res = registerModules({
|
||||||
modules: {
|
[defaultDefinition.key]: {
|
||||||
[defaultDefinition.key]: {
|
options: { test: 123 },
|
||||||
options: { test: 123 },
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
@@ -189,13 +177,11 @@ describe("module definitions loader", () => {
|
|||||||
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
MODULE_DEFINITIONS.push({ ...defaultDefinition })
|
||||||
|
|
||||||
const res = registerModules({
|
const res = registerModules({
|
||||||
modules: {
|
[defaultDefinition.key]: {
|
||||||
[defaultDefinition.key]: {
|
resolve: defaultDefinition.defaultPackage,
|
||||||
resolve: defaultDefinition.defaultPackage,
|
options: { test: 123 },
|
||||||
options: { test: 123 },
|
scope: "internal",
|
||||||
scope: "internal",
|
resources: "isolated",
|
||||||
resources: "isolated",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
import resolveCwd from "resolve-cwd"
|
import resolveCwd from "resolve-cwd"
|
||||||
|
|
||||||
|
import MODULE_DEFINITIONS from "../definitions"
|
||||||
import {
|
import {
|
||||||
MedusaModuleConfig,
|
ExternalModuleDeclaration,
|
||||||
InternalModuleDeclaration,
|
InternalModuleDeclaration,
|
||||||
ModuleDefinition,
|
ModuleDefinition,
|
||||||
ModuleResolution,
|
ModuleResolution,
|
||||||
MODULE_SCOPE,
|
MODULE_SCOPE,
|
||||||
} from "../types"
|
} from "../types"
|
||||||
import MODULE_DEFINITIONS from "../definitions"
|
|
||||||
|
|
||||||
export const registerModules = ({
|
export const registerModules = (
|
||||||
modules,
|
modules?: Record<
|
||||||
}: MedusaModuleConfig): Record<string, ModuleResolution> => {
|
string,
|
||||||
|
| false
|
||||||
|
| string
|
||||||
|
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
|
||||||
|
>
|
||||||
|
): Record<string, ModuleResolution> => {
|
||||||
const moduleResolutions = {} as Record<string, ModuleResolution>
|
const moduleResolutions = {} as Record<string, ModuleResolution>
|
||||||
const projectModules = modules ?? {}
|
const projectModules = modules ?? {}
|
||||||
|
|
||||||
@@ -26,10 +31,32 @@ export const registerModules = ({
|
|||||||
|
|
||||||
moduleResolutions[definition.key] = getInternalModuleResolution(
|
moduleResolutions[definition.key] = getInternalModuleResolution(
|
||||||
definition,
|
definition,
|
||||||
projectModules[definition.key] as
|
customConfig as InternalModuleDeclaration
|
||||||
| InternalModuleDeclaration
|
)
|
||||||
| false
|
}
|
||||||
| string
|
|
||||||
|
return moduleResolutions
|
||||||
|
}
|
||||||
|
|
||||||
|
export const registerMedusaModule = (
|
||||||
|
moduleKey: string,
|
||||||
|
moduleDeclaration: InternalModuleDeclaration | ExternalModuleDeclaration
|
||||||
|
): Record<string, ModuleResolution> => {
|
||||||
|
const moduleResolutions = {} as Record<string, ModuleResolution>
|
||||||
|
|
||||||
|
for (const definition of MODULE_DEFINITIONS) {
|
||||||
|
if (definition.key !== moduleKey) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleDeclaration.scope === MODULE_SCOPE.EXTERNAL) {
|
||||||
|
// TODO: getExternalModuleResolution(...)a
|
||||||
|
throw new Error("External Modules are not supported yet.")
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleResolutions[definition.key] = getInternalModuleResolution(
|
||||||
|
definition,
|
||||||
|
moduleDeclaration as InternalModuleDeclaration
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export async function loadInternalModule(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
error: new Error(
|
error: new Error(
|
||||||
"No service found in module. Make sure your module exports at least one service."
|
"No service found in module. Make sure your module exports a service."
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,3 +112,15 @@ export async function loadInternalModule(
|
|||||||
"module"
|
"module"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function loadModuleMigrations(
|
||||||
|
resolution: ModuleResolution
|
||||||
|
): Promise<[Function | undefined, Function | undefined]> {
|
||||||
|
let loadedModule: ModuleExports
|
||||||
|
try {
|
||||||
|
loadedModule = (await import(resolution.resolutionPath as string)).default
|
||||||
|
return [loadedModule.runMigrations, loadedModule.revertMigration]
|
||||||
|
} catch {
|
||||||
|
return [undefined, undefined]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { asValue } from "awilix"
|
||||||
|
import { createMedusaContainer } from "medusa-core-utils"
|
||||||
|
import { moduleLoader, registerMedusaModule } from "./loaders"
|
||||||
|
import { loadModuleMigrations } from "./loaders/utils"
|
||||||
|
import {
|
||||||
|
ExternalModuleDeclaration,
|
||||||
|
InternalModuleDeclaration,
|
||||||
|
MODULE_RESOURCE_TYPE,
|
||||||
|
MODULE_SCOPE,
|
||||||
|
} from "./types"
|
||||||
|
|
||||||
|
const logger: any = {
|
||||||
|
log: (a) => console.log(a),
|
||||||
|
info: (a) => console.log(a),
|
||||||
|
warn: (a) => console.warn(a),
|
||||||
|
error: (a) => console.error(a),
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MedusaModule {
|
||||||
|
public static async bootstrap(
|
||||||
|
moduleKey: string,
|
||||||
|
defaultPath: string,
|
||||||
|
declaration?: InternalModuleDeclaration | ExternalModuleDeclaration,
|
||||||
|
injectedDependencies?: Record<string, any>
|
||||||
|
): Promise<{
|
||||||
|
[key: string]: any
|
||||||
|
}> {
|
||||||
|
let modDeclaration = declaration
|
||||||
|
if (declaration?.scope !== MODULE_SCOPE.EXTERNAL) {
|
||||||
|
modDeclaration = {
|
||||||
|
scope: MODULE_SCOPE.INTERNAL,
|
||||||
|
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
||||||
|
resolve: defaultPath,
|
||||||
|
options: declaration,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = createMedusaContainer()
|
||||||
|
|
||||||
|
if (injectedDependencies) {
|
||||||
|
for (const service in injectedDependencies) {
|
||||||
|
container.register(service, asValue(injectedDependencies[service]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleResolutions = registerMedusaModule(moduleKey, modDeclaration!)
|
||||||
|
|
||||||
|
await moduleLoader({ container, moduleResolutions, logger })
|
||||||
|
|
||||||
|
const services = {}
|
||||||
|
|
||||||
|
for (const resolution of Object.values(moduleResolutions)) {
|
||||||
|
const registrationName = resolution.definition.registrationName
|
||||||
|
|
||||||
|
services[registrationName] = container.resolve(registrationName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return services
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async migrateUp(
|
||||||
|
moduleKey: string,
|
||||||
|
modulePath: string,
|
||||||
|
options?: Record<string, any>
|
||||||
|
): Promise<void> {
|
||||||
|
const moduleResolutions = registerMedusaModule(moduleKey, {
|
||||||
|
scope: MODULE_SCOPE.INTERNAL,
|
||||||
|
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
||||||
|
resolve: modulePath,
|
||||||
|
options,
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const mod in moduleResolutions) {
|
||||||
|
const [migrateUp] = await loadModuleMigrations(moduleResolutions[mod])
|
||||||
|
|
||||||
|
if (typeof migrateUp === "function") {
|
||||||
|
await migrateUp({
|
||||||
|
options,
|
||||||
|
logger,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async migrateDown(
|
||||||
|
moduleKey: string,
|
||||||
|
modulePath: string,
|
||||||
|
options?: Record<string, any>
|
||||||
|
): Promise<void> {
|
||||||
|
const moduleResolutions = registerMedusaModule(moduleKey, {
|
||||||
|
scope: MODULE_SCOPE.INTERNAL,
|
||||||
|
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
||||||
|
resolve: modulePath,
|
||||||
|
options,
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const mod in moduleResolutions) {
|
||||||
|
const [, migrateDown] = await loadModuleMigrations(moduleResolutions[mod])
|
||||||
|
|
||||||
|
if (typeof migrateDown === "function") {
|
||||||
|
await migrateDown({
|
||||||
|
options,
|
||||||
|
logger,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -68,9 +68,9 @@ export type ModuleDefinition = {
|
|||||||
| ExternalModuleDeclaration
|
| ExternalModuleDeclaration
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LoaderOptions = {
|
export type LoaderOptions<TOptions = Record<string, unknown>> = {
|
||||||
container: MedusaContainer
|
container: MedusaContainer
|
||||||
options?: Record<string, unknown>
|
options?: TOptions
|
||||||
logger?: Logger
|
logger?: Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,13 +89,12 @@ export type ModuleExports = {
|
|||||||
loaders?: ModuleLoaderFunction[]
|
loaders?: ModuleLoaderFunction[]
|
||||||
migrations?: any[]
|
migrations?: any[]
|
||||||
models?: Constructor<any>[]
|
models?: Constructor<any>[]
|
||||||
}
|
runMigrations?(
|
||||||
|
options: LoaderOptions,
|
||||||
export type MedusaModuleConfig = {
|
moduleDeclaration: InternalModuleDeclaration
|
||||||
modules?: Record<
|
): Promise<void>
|
||||||
string,
|
revertMigration?(
|
||||||
| false
|
options: LoaderOptions,
|
||||||
| string
|
moduleDeclaration: InternalModuleDeclaration
|
||||||
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
|
): Promise<void>
|
||||||
>
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
|
import { ModuleExports } from "@medusajs/modules-sdk"
|
||||||
import loadConnection from "./loaders/connection"
|
import loadConnection from "./loaders/connection"
|
||||||
|
|
||||||
import migrations from "./migrations"
|
import migrations from "./migrations"
|
||||||
|
import { revertMigration, runMigrations } from "./migrations/run-migration"
|
||||||
import * as StockLocationModels from "./models"
|
import * as StockLocationModels from "./models"
|
||||||
import StockLocationService from "./services/stock-location"
|
import StockLocationService from "./services/stock-location"
|
||||||
|
|
||||||
import { ModuleExports } from "@medusajs/modules-sdk"
|
|
||||||
|
|
||||||
const service = StockLocationService
|
const service = StockLocationService
|
||||||
const loaders = [loadConnection]
|
const loaders = [loadConnection]
|
||||||
const models = Object.values(StockLocationModels)
|
const models = Object.values(StockLocationModels)
|
||||||
@@ -15,6 +14,8 @@ const moduleDefinition: ModuleExports = {
|
|||||||
migrations,
|
migrations,
|
||||||
loaders,
|
loaders,
|
||||||
models,
|
models,
|
||||||
|
runMigrations,
|
||||||
|
revertMigration,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default moduleDefinition
|
export default moduleDefinition
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { IEventBusService, IStockLocationService } from "@medusajs/medusa"
|
||||||
|
import {
|
||||||
|
ExternalModuleDeclaration,
|
||||||
|
InternalModuleDeclaration,
|
||||||
|
MedusaModule,
|
||||||
|
} from "@medusajs/modules-sdk"
|
||||||
|
import { StockLocationServiceInitializeOptions } from "../types"
|
||||||
|
|
||||||
|
export const initialize = async (
|
||||||
|
options?: StockLocationServiceInitializeOptions | ExternalModuleDeclaration,
|
||||||
|
injectedDependencies?: {
|
||||||
|
eventBusService: IEventBusService
|
||||||
|
}
|
||||||
|
): Promise<IStockLocationService> => {
|
||||||
|
const serviceKey = "stockLocationService"
|
||||||
|
const loaded = await MedusaModule.bootstrap(
|
||||||
|
serviceKey,
|
||||||
|
"@medusajs/stock-location",
|
||||||
|
options as InternalModuleDeclaration | ExternalModuleDeclaration,
|
||||||
|
injectedDependencies
|
||||||
|
)
|
||||||
|
|
||||||
|
return loaded[serviceKey] as IStockLocationService
|
||||||
|
}
|
||||||
@@ -2,13 +2,13 @@ import {
|
|||||||
InternalModuleDeclaration,
|
InternalModuleDeclaration,
|
||||||
LoaderOptions,
|
LoaderOptions,
|
||||||
MODULE_RESOURCE_TYPE,
|
MODULE_RESOURCE_TYPE,
|
||||||
MODULE_SCOPE,
|
MODULE_SCOPE
|
||||||
} from "@medusajs/modules-sdk"
|
} from "@medusajs/modules-sdk"
|
||||||
import { DataSource, DataSourceOptions } from "typeorm"
|
|
||||||
|
|
||||||
import * as StockLocationModels from "../models"
|
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
import { asValue } from "awilix"
|
import { asValue } from "awilix"
|
||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
import { DataSource, DataSourceOptions } from "typeorm"
|
||||||
|
import * as StockLocationModels from "../models"
|
||||||
|
import { StockLocationServiceInitializeOptions } from "../types"
|
||||||
|
|
||||||
export default async (
|
export default async (
|
||||||
{ options, container }: LoaderOptions,
|
{ options, container }: LoaderOptions,
|
||||||
@@ -21,7 +21,8 @@ export default async (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const dbData = options?.database as Record<string, string>
|
const dbData =
|
||||||
|
options?.database as StockLocationServiceInitializeOptions["database"]
|
||||||
|
|
||||||
if (!dbData) {
|
if (!dbData) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -32,13 +33,13 @@ export default async (
|
|||||||
|
|
||||||
const entities = Object.values(StockLocationModels)
|
const entities = Object.values(StockLocationModels)
|
||||||
const dataSource = new DataSource({
|
const dataSource = new DataSource({
|
||||||
type: dbData.database_type,
|
type: dbData.type,
|
||||||
url: dbData.database_url,
|
url: dbData.url,
|
||||||
database: dbData.database_database,
|
database: dbData.database,
|
||||||
extra: dbData.database_extra || {},
|
extra: dbData.extra || {},
|
||||||
schema: dbData.database_schema,
|
schema: dbData.schema,
|
||||||
entities,
|
entities,
|
||||||
logging: dbData.database_logging,
|
logging: dbData.logging,
|
||||||
} as DataSourceOptions)
|
} as DataSourceOptions)
|
||||||
|
|
||||||
await dataSource.initialize()
|
await dataSource.initialize()
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { InternalModuleDeclaration, LoaderOptions } from "@medusajs/modules-sdk"
|
||||||
|
import { DataSource, DataSourceOptions } from "typeorm"
|
||||||
|
import { StockLocationServiceInitializeOptions } from "../types"
|
||||||
|
|
||||||
|
import migrations from "./index"
|
||||||
|
|
||||||
|
function getDataSource(
|
||||||
|
dbData: StockLocationServiceInitializeOptions["database"]
|
||||||
|
): DataSource {
|
||||||
|
return new DataSource({
|
||||||
|
type: dbData!.type,
|
||||||
|
url: dbData!.url,
|
||||||
|
database: dbData!.database,
|
||||||
|
extra: dbData!.extra || {},
|
||||||
|
migrations: migrations
|
||||||
|
.map((migration: any): Function[] => {
|
||||||
|
return Object.values(migration).filter(
|
||||||
|
(fn) => typeof fn === "function"
|
||||||
|
) as Function[]
|
||||||
|
})
|
||||||
|
.flat(),
|
||||||
|
schema: dbData!.schema,
|
||||||
|
logging: dbData!.logging,
|
||||||
|
} as DataSourceOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function runMigrations(
|
||||||
|
{ options, logger }: Omit<LoaderOptions, "container">,
|
||||||
|
moduleDeclaration?: InternalModuleDeclaration
|
||||||
|
) {
|
||||||
|
const dbData =
|
||||||
|
options?.database as StockLocationServiceInitializeOptions["database"]
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dataSource = getDataSource(dbData)
|
||||||
|
await dataSource.initialize()
|
||||||
|
await dataSource.runMigrations()
|
||||||
|
|
||||||
|
logger?.info("Stock Location module migration executed")
|
||||||
|
} catch (error) {
|
||||||
|
logger?.error(
|
||||||
|
`Stock Location module migration failed to run - Error: ${error}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function revertMigration(
|
||||||
|
{ options, logger }: Omit<LoaderOptions, "container">,
|
||||||
|
moduleDeclaration?: InternalModuleDeclaration
|
||||||
|
) {
|
||||||
|
const dbData =
|
||||||
|
options?.database as StockLocationServiceInitializeOptions["database"]
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dataSource = getDataSource(dbData)
|
||||||
|
await dataSource.initialize()
|
||||||
|
await dataSource.undoLastMigration()
|
||||||
|
|
||||||
|
logger?.info("Stock Location module migration reverted")
|
||||||
|
} catch (error) {
|
||||||
|
logger?.error(
|
||||||
|
`Stock Location module migration failed to revert - Error: ${error}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -153,11 +153,9 @@ export default class StockLocationService {
|
|||||||
}
|
}
|
||||||
const result = await locationRepo.save(loc)
|
const result = await locationRepo.save(loc)
|
||||||
|
|
||||||
await this.eventBusService_
|
await this.eventBusService_?.emit?.(StockLocationService.Events.CREATED, {
|
||||||
.withTransaction(manager)
|
id: result.id,
|
||||||
.emit(StockLocationService.Events.CREATED, {
|
})
|
||||||
id: result.id,
|
|
||||||
})
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -201,11 +199,9 @@ export default class StockLocationService {
|
|||||||
|
|
||||||
await locationRepo.save(toSave)
|
await locationRepo.save(toSave)
|
||||||
|
|
||||||
await this.eventBusService_
|
await this.eventBusService_?.emit?.(StockLocationService.Events.UPDATED, {
|
||||||
.withTransaction(manager)
|
id: stockLocationId,
|
||||||
.emit(StockLocationService.Events.UPDATED, {
|
})
|
||||||
id: stockLocationId,
|
|
||||||
})
|
|
||||||
|
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
@@ -267,10 +263,8 @@ export default class StockLocationService {
|
|||||||
|
|
||||||
await locationRepo.softRemove({ id })
|
await locationRepo.softRemove({ id })
|
||||||
|
|
||||||
await this.eventBusService_
|
await this.eventBusService_?.emit?.(StockLocationService.Events.DELETED, {
|
||||||
.withTransaction(manager)
|
id,
|
||||||
.emit(StockLocationService.Events.DELETED, {
|
})
|
||||||
id,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { DatabaseType } from "typeorm"
|
||||||
|
|
||||||
|
export type StockLocationServiceInitializeOptions = {
|
||||||
|
database?: {
|
||||||
|
type?: DatabaseType | string
|
||||||
|
url?: string
|
||||||
|
database?: string
|
||||||
|
extra?: Record<string, any>
|
||||||
|
schema?: string
|
||||||
|
logging?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,16 +4,16 @@ export function MedusaContext() {
|
|||||||
propertyKey: string | symbol,
|
propertyKey: string | symbol,
|
||||||
parameterIndex: number
|
parameterIndex: number
|
||||||
) {
|
) {
|
||||||
if (!target.MedusaContext_) {
|
if (!target.MedusaContextIndex_) {
|
||||||
target.MedusaContext_ = {}
|
target.MedusaContextIndex_ = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propertyKey in target.MedusaContext_) {
|
if (propertyKey in target.MedusaContextIndex_) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Only one MedusaContext is allowed on method "${String(propertyKey)}".`
|
`Only one MedusaContext is allowed on method "${String(propertyKey)}".`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
target.MedusaContext_[propertyKey] = parameterIndex
|
target.MedusaContextIndex_[propertyKey] = parameterIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export function InjectEntityManager(
|
|||||||
propertyKey: string | symbol,
|
propertyKey: string | symbol,
|
||||||
descriptor: any
|
descriptor: any
|
||||||
): void {
|
): void {
|
||||||
if (!target.MedusaContext_) {
|
if (!target.MedusaContextIndex_) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`To apply @InjectEntityManager you have to flag a parameter using @MedusaContext`
|
`To apply @InjectEntityManager you have to flag a parameter using @MedusaContext`
|
||||||
)
|
)
|
||||||
@@ -16,7 +16,7 @@ export function InjectEntityManager(
|
|||||||
|
|
||||||
const originalMethod = descriptor.value
|
const originalMethod = descriptor.value
|
||||||
|
|
||||||
const argIndex = target.MedusaContext_[propertyKey]
|
const argIndex = target.MedusaContextIndex_[propertyKey]
|
||||||
descriptor.value = async function (...args: any[]) {
|
descriptor.value = async function (...args: any[]) {
|
||||||
const context: SharedContext = args[argIndex] ?? {}
|
const context: SharedContext = args[argIndex] ?? {}
|
||||||
|
|
||||||
|
|||||||
@@ -5741,8 +5741,10 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@medusajs/inventory@workspace:packages/inventory"
|
resolution: "@medusajs/inventory@workspace:packages/inventory"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@medusajs/medusa": "*"
|
"@medusajs/medusa": ^1.7.7
|
||||||
"@medusajs/modules-sdk": "*"
|
"@medusajs/modules-sdk": "*"
|
||||||
|
"@medusajs/types": "*"
|
||||||
|
"@medusajs/utils": ^0.0.1
|
||||||
awilix: ^8.0.0
|
awilix: ^8.0.0
|
||||||
cross-env: ^5.2.1
|
cross-env: ^5.2.1
|
||||||
jest: ^25.5.4
|
jest: ^25.5.4
|
||||||
@@ -5750,7 +5752,7 @@ __metadata:
|
|||||||
typeorm: ^0.3.11
|
typeorm: ^0.3.11
|
||||||
typescript: ^4.4.4
|
typescript: ^4.4.4
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@medusajs/medusa": 1.7.13
|
"@medusajs/types": ^0.0.1
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user