chore: added missing withTransacton, create-variant using TO (#3047)
Create variant integrated with Inventory modules
This commit is contained in:
@@ -1,53 +1,68 @@
|
|||||||
if (process.env.NODE_ENV !== "development") {
|
if (process.env.NODE_ENV !== "development") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = require("path")
|
const path = require("path")
|
||||||
|
|
||||||
const Module = require("module")
|
const Module = require("module")
|
||||||
const originalRequire = Module.prototype.require
|
const originalRequire = Module.prototype.require
|
||||||
const medusaCore = path.resolve(path.join(__dirname, "../../packages"))
|
const medusaCore = path.resolve(path.join(__dirname, "../../packages"))
|
||||||
|
|
||||||
function replacePath(requirePath, package, concatPackage = true) {
|
function replacePath(requirePath, pack, concatPackage = true) {
|
||||||
const idx = requirePath.indexOf(package)
|
const idx = requirePath.indexOf(pack)
|
||||||
const packPath = requirePath.substring(idx + package.length)
|
const packPath = requirePath.substring(idx + pack.length).replace(/\\/g, "/")
|
||||||
|
|
||||||
let newPath =
|
let newPath =
|
||||||
medusaCore +
|
medusaCore +
|
||||||
"/" +
|
"/" +
|
||||||
(concatPackage ? package + "/" : "") +
|
(concatPackage ? pack + "/" : "") +
|
||||||
packPath.replace("/dist", "/src").replace(".js", "")
|
packPath.replace("/dist", "/src").replace(".js", "")
|
||||||
|
|
||||||
if (!newPath.includes("/src")) {
|
if (!newPath.includes("/src")) {
|
||||||
newPath += "/src"
|
newPath += "/src"
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.resolve(newPath)
|
return path.resolve(newPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
Module.prototype.require = function (...args) {
|
function checkAndReplacePaths(path) {
|
||||||
const interfaces = "medusa-interfaces"
|
const interfaces = "medusa-interfaces"
|
||||||
const utils = "medusa-core-utils"
|
const utils = "medusa-core-utils"
|
||||||
const base = "@medusajs"
|
const base = "@medusajs"
|
||||||
|
|
||||||
if (args[0].includes(base)) {
|
if (path.includes(base)) {
|
||||||
args[0] = replacePath(args[0], base, false)
|
path = replacePath(path, base, false)
|
||||||
} else if (args[0].includes(interfaces)) {
|
} else if (path.includes(interfaces)) {
|
||||||
args[0] = replacePath(args[0], interfaces)
|
path = replacePath(path, interfaces)
|
||||||
} else if (args[0].includes(utils)) {
|
} else if (path.includes(utils)) {
|
||||||
args[0] = replacePath(args[0], utils)
|
path = replacePath(path, utils)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
Module.prototype.require = function (...args) {
|
||||||
|
args[0] = checkAndReplacePaths(args[0])
|
||||||
|
|
||||||
if (args[0] === "glob") {
|
if (args[0] === "glob") {
|
||||||
const glob = originalRequire.apply(this, args)
|
const glob = originalRequire.apply(this, args)
|
||||||
const originalGlobSync = glob.sync
|
const originalGlobSync = glob.sync
|
||||||
glob.GlobSync = glob.sync = (pattern, options) => {
|
glob.GlobSync = glob.sync = (pattern, options) => {
|
||||||
if (pattern.endsWith(".js") || pattern.endsWith(".ts")) {
|
if (pattern.endsWith(".js") || pattern.endsWith(".ts")) {
|
||||||
|
pattern = checkAndReplacePaths(pattern)
|
||||||
pattern = pattern.replace(".js", ".{j,t}s").replace("/dist/", "/src/")
|
pattern = pattern.replace(".js", ".{j,t}s").replace("/dist/", "/src/")
|
||||||
}
|
}
|
||||||
|
|
||||||
return originalGlobSync.apply(this, [pattern, options])
|
return originalGlobSync.apply(this, [pattern, options])
|
||||||
}
|
}
|
||||||
return glob
|
return glob
|
||||||
|
} else if (args[0] === "resolve-cwd") {
|
||||||
|
const resolveCwd = originalRequire.apply(this, args)
|
||||||
|
const newResolveCwd = (pattern) => {
|
||||||
|
pattern = checkAndReplacePaths(pattern)
|
||||||
|
|
||||||
|
return resolveCwd.apply(this, [pattern])
|
||||||
|
}
|
||||||
|
return newResolveCwd
|
||||||
}
|
}
|
||||||
|
|
||||||
return originalRequire.apply(this, args)
|
return originalRequire.apply(this, args)
|
||||||
|
|||||||
@@ -14,6 +14,22 @@ const medusaCore = path
|
|||||||
.replace(/\\/g, "/")
|
.replace(/\\/g, "/")
|
||||||
|
|
||||||
let WATCHING = false
|
let WATCHING = false
|
||||||
|
let IS_RELOADING = false
|
||||||
|
|
||||||
|
function getParentModulesIds(element) {
|
||||||
|
if (!element) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const ids = [element.id]
|
||||||
|
let parent = element.parent
|
||||||
|
while (parent && parent.id.replace(/\\/g, "/").includes(medusaCore)) {
|
||||||
|
ids.push(parent.id)
|
||||||
|
parent = parent.parent
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
const watchFiles = () => {
|
const watchFiles = () => {
|
||||||
if (WATCHING) {
|
if (WATCHING) {
|
||||||
return
|
return
|
||||||
@@ -42,7 +58,12 @@ const watchFiles = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
watcher.on("change", async function (rawFile) {
|
watcher.on("change", async function (rawFile) {
|
||||||
|
if (IS_RELOADING) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Reloading server...")
|
console.log("Reloading server...")
|
||||||
|
IS_RELOADING = true
|
||||||
const start = Date.now()
|
const start = Date.now()
|
||||||
|
|
||||||
const file = rawFile.replace(/\\/g, "/")
|
const file = rawFile.replace(/\\/g, "/")
|
||||||
@@ -75,12 +96,18 @@ const watchFiles = () => {
|
|||||||
next.endsWith(".ts") ||
|
next.endsWith(".ts") ||
|
||||||
name.startsWith(next)
|
name.startsWith(next)
|
||||||
) {
|
) {
|
||||||
delete module.constructor._cache[rawName]
|
const cacheToClean = getParentModulesIds(
|
||||||
|
module.constructor._cache[rawName]
|
||||||
|
)
|
||||||
|
for (const id of cacheToClean) {
|
||||||
|
delete module.constructor._cache[id]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await bootstrapApp()
|
await bootstrapApp()
|
||||||
|
IS_RELOADING = false
|
||||||
|
|
||||||
console.log("Server reloaded in", Date.now() - start, "ms")
|
console.log("Server reloaded in", Date.now() - start, "ms")
|
||||||
})
|
})
|
||||||
@@ -119,8 +146,6 @@ const bootstrapApp = async () => {
|
|||||||
watchFiles()
|
watchFiles()
|
||||||
console.log(`Server Running at localhost:${port}`)
|
console.log(`Server Running at localhost:${port}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
database = dbConnection
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrapApp()
|
void bootstrapApp()
|
||||||
|
|||||||
+1
-1
@@ -66,7 +66,7 @@ export class inventorySetup1665748086258 implements MigrationInterface {
|
|||||||
CONSTRAINT "PK_inventory_item_id" PRIMARY KEY ("id")
|
CONSTRAINT "PK_inventory_item_id" PRIMARY KEY ("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE UNIQUE INDEX "IDX_inventory_item_sku" ON "inventory_item" ("sku");
|
CREATE UNIQUE INDEX "IDX_inventory_item_sku" ON "inventory_item" ("sku") WHERE deleted_at IS NULL;
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE "reservation_item" (
|
CREATE TABLE "reservation_item" (
|
||||||
|
|||||||
@@ -75,6 +75,10 @@ export default class InventoryService
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getManager(): EntityManager {
|
||||||
|
return this.transactionManager_ ?? this.manager_
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists inventory items that match the given selector
|
* Lists inventory items that match the given selector
|
||||||
* @param selector - the selector to filter inventory items by
|
* @param selector - the selector to filter inventory items by
|
||||||
@@ -85,7 +89,9 @@ export default class InventoryService
|
|||||||
selector: FilterableInventoryItemProps,
|
selector: FilterableInventoryItemProps,
|
||||||
config: FindConfig<InventoryItemDTO> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<InventoryItemDTO> = { relations: [], skip: 0, take: 10 }
|
||||||
): Promise<[InventoryItemDTO[], number]> {
|
): Promise<[InventoryItemDTO[], number]> {
|
||||||
return await this.inventoryItemService_.listAndCount(selector, config)
|
return await this.inventoryItemService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.listAndCount(selector, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,7 +104,9 @@ export default class InventoryService
|
|||||||
selector: FilterableInventoryLevelProps,
|
selector: FilterableInventoryLevelProps,
|
||||||
config: FindConfig<InventoryLevelDTO> = { relations: [], skip: 0, take: 10 }
|
config: FindConfig<InventoryLevelDTO> = { relations: [], skip: 0, take: 10 }
|
||||||
): Promise<[InventoryLevelDTO[], number]> {
|
): Promise<[InventoryLevelDTO[], number]> {
|
||||||
return await this.inventoryLevelService_.listAndCount(selector, config)
|
return await this.inventoryLevelService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.listAndCount(selector, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,7 +123,9 @@ export default class InventoryService
|
|||||||
take: 10,
|
take: 10,
|
||||||
}
|
}
|
||||||
): Promise<[ReservationItemDTO[], number]> {
|
): Promise<[ReservationItemDTO[], number]> {
|
||||||
return await this.reservationItemService_.listAndCount(selector, config)
|
return await this.reservationItemService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.listAndCount(selector, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,10 +138,9 @@ export default class InventoryService
|
|||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
config?: FindConfig<InventoryItemDTO>
|
config?: FindConfig<InventoryItemDTO>
|
||||||
): Promise<InventoryItemDTO> {
|
): Promise<InventoryItemDTO> {
|
||||||
const inventoryItem = await this.inventoryItemService_.retrieve(
|
const inventoryItem = await this.inventoryItemService_
|
||||||
inventoryItemId,
|
.withTransaction(this.getManager())
|
||||||
config
|
.retrieve(inventoryItemId, config)
|
||||||
)
|
|
||||||
return { ...inventoryItem }
|
return { ...inventoryItem }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,10 +154,12 @@ export default class InventoryService
|
|||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationId: string
|
locationId: string
|
||||||
): Promise<InventoryLevelDTO> {
|
): Promise<InventoryLevelDTO> {
|
||||||
const [inventoryLevel] = await this.inventoryLevelService_.list(
|
const [inventoryLevel] = await this.inventoryLevelService_
|
||||||
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
.withTransaction(this.getManager())
|
||||||
{ take: 1 }
|
.list(
|
||||||
)
|
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
||||||
|
{ take: 1 }
|
||||||
|
)
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.NOT_FOUND,
|
MedusaError.Types.NOT_FOUND,
|
||||||
@@ -167,13 +178,15 @@ export default class InventoryService
|
|||||||
input: CreateReservationItemInput
|
input: CreateReservationItemInput
|
||||||
): 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_.list(
|
const [inventoryLevel] = await this.inventoryLevelService_
|
||||||
{
|
.withTransaction(this.getManager())
|
||||||
inventory_item_id: input.inventory_item_id,
|
.list(
|
||||||
location_id: input.location_id,
|
{
|
||||||
},
|
inventory_item_id: input.inventory_item_id,
|
||||||
{ take: 1 }
|
location_id: input.location_id,
|
||||||
)
|
},
|
||||||
|
{ take: 1 }
|
||||||
|
)
|
||||||
|
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -182,7 +195,9 @@ export default class InventoryService
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const reservationItem = await this.reservationItemService_.create(input)
|
const reservationItem = await this.reservationItemService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.create(input)
|
||||||
|
|
||||||
return { ...reservationItem }
|
return { ...reservationItem }
|
||||||
}
|
}
|
||||||
@@ -195,7 +210,9 @@ export default class InventoryService
|
|||||||
async createInventoryItem(
|
async createInventoryItem(
|
||||||
input: CreateInventoryItemInput
|
input: CreateInventoryItemInput
|
||||||
): Promise<InventoryItemDTO> {
|
): Promise<InventoryItemDTO> {
|
||||||
const inventoryItem = await this.inventoryItemService_.create(input)
|
const inventoryItem = await this.inventoryItemService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.create(input)
|
||||||
return { ...inventoryItem }
|
return { ...inventoryItem }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +224,9 @@ export default class InventoryService
|
|||||||
async createInventoryLevel(
|
async createInventoryLevel(
|
||||||
input: CreateInventoryLevelInput
|
input: CreateInventoryLevelInput
|
||||||
): Promise<InventoryLevelDTO> {
|
): Promise<InventoryLevelDTO> {
|
||||||
return await this.inventoryLevelService_.create(input)
|
return await this.inventoryLevelService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.create(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,10 +239,9 @@ export default class InventoryService
|
|||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
input: Partial<CreateInventoryItemInput>
|
input: Partial<CreateInventoryItemInput>
|
||||||
): Promise<InventoryItemDTO> {
|
): Promise<InventoryItemDTO> {
|
||||||
const inventoryItem = await this.inventoryItemService_.update(
|
const inventoryItem = await this.inventoryItemService_
|
||||||
inventoryItemId,
|
.withTransaction(this.getManager())
|
||||||
input
|
.update(inventoryItemId, input)
|
||||||
)
|
|
||||||
return { ...inventoryItem }
|
return { ...inventoryItem }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +250,9 @@ export default class InventoryService
|
|||||||
* @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> {
|
async deleteInventoryItem(inventoryItemId: string): Promise<void> {
|
||||||
return await this.inventoryItemService_.delete(inventoryItemId)
|
return await this.inventoryItemService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.delete(inventoryItemId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,16 +264,20 @@ export default class InventoryService
|
|||||||
inventoryItemId: string,
|
inventoryItemId: string,
|
||||||
locationId: string
|
locationId: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const [inventoryLevel] = await this.inventoryLevelService_.list(
|
const [inventoryLevel] = await this.inventoryLevelService_
|
||||||
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
.withTransaction(this.getManager())
|
||||||
{ take: 1 }
|
.list(
|
||||||
)
|
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
||||||
|
{ take: 1 }
|
||||||
|
)
|
||||||
|
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.inventoryLevelService_.delete(inventoryLevel.id)
|
return await this.inventoryLevelService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.delete(inventoryLevel.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -268,10 +292,12 @@ export default class InventoryService
|
|||||||
locationId: string,
|
locationId: string,
|
||||||
input: UpdateInventoryLevelInput
|
input: UpdateInventoryLevelInput
|
||||||
): Promise<InventoryLevelDTO> {
|
): Promise<InventoryLevelDTO> {
|
||||||
const [inventoryLevel] = await this.inventoryLevelService_.list(
|
const [inventoryLevel] = await this.inventoryLevelService_
|
||||||
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
.withTransaction(this.getManager())
|
||||||
{ take: 1 }
|
.list(
|
||||||
)
|
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
||||||
|
{ take: 1 }
|
||||||
|
)
|
||||||
|
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -280,7 +306,9 @@ export default class InventoryService
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.inventoryLevelService_.update(inventoryLevel.id, input)
|
return await this.inventoryLevelService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.update(inventoryLevel.id, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -293,7 +321,9 @@ export default class InventoryService
|
|||||||
reservationItemId: string,
|
reservationItemId: string,
|
||||||
input: UpdateReservationItemInput
|
input: UpdateReservationItemInput
|
||||||
): Promise<ReservationItemDTO> {
|
): Promise<ReservationItemDTO> {
|
||||||
return await this.reservationItemService_.update(reservationItemId, input)
|
return await this.reservationItemService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.update(reservationItemId, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -301,7 +331,9 @@ export default class InventoryService
|
|||||||
* @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> {
|
async deleteReservationItemsByLineItem(lineItemId: string): Promise<void> {
|
||||||
return await this.reservationItemService_.deleteByLineItem(lineItemId)
|
return await this.reservationItemService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.deleteByLineItem(lineItemId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -309,7 +341,9 @@ export default class InventoryService
|
|||||||
* @param reservationItemId - the id of the reservation item to delete
|
* @param reservationItemId - the id of the reservation item to delete
|
||||||
*/
|
*/
|
||||||
async deleteReservationItem(reservationItemId: string): Promise<void> {
|
async deleteReservationItem(reservationItemId: string): Promise<void> {
|
||||||
return await this.reservationItemService_.delete(reservationItemId)
|
return await this.reservationItemService_
|
||||||
|
.withTransaction(this.getManager())
|
||||||
|
.delete(reservationItemId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -325,10 +359,12 @@ export default class InventoryService
|
|||||||
locationId: string,
|
locationId: string,
|
||||||
adjustment: number
|
adjustment: number
|
||||||
): Promise<InventoryLevelDTO> {
|
): Promise<InventoryLevelDTO> {
|
||||||
const [inventoryLevel] = await this.inventoryLevelService_.list(
|
const [inventoryLevel] = await this.inventoryLevelService_
|
||||||
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
.withTransaction(this.getManager())
|
||||||
{ take: 1 }
|
.list(
|
||||||
)
|
{ inventory_item_id: inventoryItemId, location_id: locationId },
|
||||||
|
{ take: 1 }
|
||||||
|
)
|
||||||
if (!inventoryLevel) {
|
if (!inventoryLevel) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.NOT_FOUND,
|
MedusaError.Types.NOT_FOUND,
|
||||||
@@ -336,12 +372,11 @@ export default class InventoryService
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedInventoryLevel = await this.inventoryLevelService_.update(
|
const updatedInventoryLevel = await this.inventoryLevelService_
|
||||||
inventoryLevel.id,
|
.withTransaction(this.getManager())
|
||||||
{
|
.update(inventoryLevel.id, {
|
||||||
stocked_quantity: inventoryLevel.stocked_quantity + adjustment,
|
stocked_quantity: inventoryLevel.stocked_quantity + adjustment,
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
return { ...updatedInventoryLevel }
|
return { ...updatedInventoryLevel }
|
||||||
}
|
}
|
||||||
@@ -358,15 +393,15 @@ export default class InventoryService
|
|||||||
locationIds: string[]
|
locationIds: string[]
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
// Throws if item does not exist
|
// Throws if item does not exist
|
||||||
await this.inventoryItemService_.retrieve(inventoryItemId, {
|
await this.inventoryItemService_
|
||||||
select: ["id"],
|
.withTransaction(this.getManager())
|
||||||
})
|
.retrieve(inventoryItemId, {
|
||||||
|
select: ["id"],
|
||||||
|
})
|
||||||
|
|
||||||
const availableQuantity =
|
const availableQuantity = await this.inventoryLevelService_
|
||||||
await this.inventoryLevelService_.getAvailableQuantity(
|
.withTransaction(this.getManager())
|
||||||
inventoryItemId,
|
.getAvailableQuantity(inventoryItemId, locationIds)
|
||||||
locationIds
|
|
||||||
)
|
|
||||||
|
|
||||||
return availableQuantity
|
return availableQuantity
|
||||||
}
|
}
|
||||||
@@ -383,15 +418,15 @@ export default class InventoryService
|
|||||||
locationIds: string[]
|
locationIds: string[]
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
// Throws if item does not exist
|
// Throws if item does not exist
|
||||||
await this.inventoryItemService_.retrieve(inventoryItemId, {
|
await this.inventoryItemService_
|
||||||
select: ["id"],
|
.withTransaction(this.getManager())
|
||||||
})
|
.retrieve(inventoryItemId, {
|
||||||
|
select: ["id"],
|
||||||
|
})
|
||||||
|
|
||||||
const stockedQuantity =
|
const stockedQuantity = await this.inventoryLevelService_
|
||||||
await this.inventoryLevelService_.getStockedQuantity(
|
.withTransaction(this.getManager())
|
||||||
inventoryItemId,
|
.getStockedQuantity(inventoryItemId, locationIds)
|
||||||
locationIds
|
|
||||||
)
|
|
||||||
|
|
||||||
return stockedQuantity
|
return stockedQuantity
|
||||||
}
|
}
|
||||||
@@ -408,15 +443,15 @@ export default class InventoryService
|
|||||||
locationIds: string[]
|
locationIds: string[]
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
// Throws if item does not exist
|
// Throws if item does not exist
|
||||||
await this.inventoryItemService_.retrieve(inventoryItemId, {
|
await this.inventoryItemService_
|
||||||
select: ["id"],
|
.withTransaction(this.getManager())
|
||||||
})
|
.retrieve(inventoryItemId, {
|
||||||
|
select: ["id"],
|
||||||
|
})
|
||||||
|
|
||||||
const reservedQuantity =
|
const reservedQuantity = await this.inventoryLevelService_
|
||||||
await this.inventoryLevelService_.getReservedQuantity(
|
.withTransaction(this.getManager())
|
||||||
inventoryItemId,
|
.getReservedQuantity(inventoryItemId, locationIds)
|
||||||
locationIds
|
|
||||||
)
|
|
||||||
|
|
||||||
return reservedQuantity
|
return reservedQuantity
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ describe("POST /admin/products/:id/variants", () => {
|
|||||||
IdMap.getId("productWithOptions"),
|
IdMap.getId("productWithOptions"),
|
||||||
{
|
{
|
||||||
inventory_quantity: 0,
|
inventory_quantity: 0,
|
||||||
|
manage_inventory: true,
|
||||||
title: "Test Product Variant",
|
title: "Test Product Variant",
|
||||||
options: [],
|
options: [],
|
||||||
prices: [
|
prices: [
|
||||||
|
|||||||
@@ -7,17 +7,33 @@ import {
|
|||||||
IsString,
|
IsString,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
|
||||||
import { ProductService, ProductVariantService } from "../../../../services"
|
|
||||||
|
|
||||||
import { Type } from "class-transformer"
|
import { Type } from "class-transformer"
|
||||||
import { EntityManager } from "typeorm"
|
import {
|
||||||
|
ProductService,
|
||||||
|
ProductVariantService,
|
||||||
|
ProductVariantInventoryService,
|
||||||
|
} from "../../../../services"
|
||||||
|
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
||||||
|
|
||||||
|
import { IInventoryService } from "../../../../interfaces"
|
||||||
import {
|
import {
|
||||||
CreateProductVariantInput,
|
CreateProductVariantInput,
|
||||||
ProductVariantPricesCreateReq,
|
ProductVariantPricesCreateReq,
|
||||||
} from "../../../../types/product-variant"
|
} from "../../../../types/product-variant"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
|
import {
|
||||||
|
TransactionHandlerType,
|
||||||
|
TransactionOrchestrator,
|
||||||
|
TransactionPayload,
|
||||||
|
TransactionState,
|
||||||
|
TransactionStepsDefinition,
|
||||||
|
} from "../../../../utils/transaction"
|
||||||
|
|
||||||
|
import { ulid } from "ulid"
|
||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
import { EntityManager } from "typeorm"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [post] /products/{id}/variants
|
* @oas [post] /products/{id}/variants
|
||||||
* operationId: "PostProductsProductVariants"
|
* operationId: "PostProductsProductVariants"
|
||||||
@@ -103,6 +119,48 @@ import { validator } from "../../../../utils/validator"
|
|||||||
* "500":
|
* "500":
|
||||||
* $ref: "#/components/responses/500_error"
|
* $ref: "#/components/responses/500_error"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
enum actions {
|
||||||
|
createVariant = "createVariant",
|
||||||
|
createInventoryItem = "createInventoryItem",
|
||||||
|
attachInventoryItem = "attachInventoryItem",
|
||||||
|
}
|
||||||
|
|
||||||
|
const simpleFlow: TransactionStepsDefinition = {
|
||||||
|
next: {
|
||||||
|
action: actions.createVariant,
|
||||||
|
maxRetries: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const flowWithInventory: TransactionStepsDefinition = {
|
||||||
|
next: {
|
||||||
|
action: actions.createVariant,
|
||||||
|
forwardResponse: true,
|
||||||
|
maxRetries: 0,
|
||||||
|
next: {
|
||||||
|
action: actions.createInventoryItem,
|
||||||
|
forwardResponse: true,
|
||||||
|
maxRetries: 0,
|
||||||
|
next: {
|
||||||
|
action: actions.attachInventoryItem,
|
||||||
|
noCompensation: true,
|
||||||
|
maxRetries: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const createSimpleVariantStrategy = new TransactionOrchestrator(
|
||||||
|
"create-variant",
|
||||||
|
simpleFlow
|
||||||
|
)
|
||||||
|
|
||||||
|
const createVariantStrategyWithInventory = new TransactionOrchestrator(
|
||||||
|
"create-variant-with-inventory",
|
||||||
|
flowWithInventory
|
||||||
|
)
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const { id } = req.params
|
const { id } = req.params
|
||||||
|
|
||||||
@@ -111,18 +169,140 @@ export default async (req, res) => {
|
|||||||
req.body
|
req.body
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const inventoryService: IInventoryService | undefined =
|
||||||
|
req.scope.resolve("inventoryService")
|
||||||
|
const productVariantInventoryService: ProductVariantInventoryService =
|
||||||
|
req.scope.resolve("productVariantInventoryService")
|
||||||
const productVariantService: ProductVariantService = req.scope.resolve(
|
const productVariantService: ProductVariantService = req.scope.resolve(
|
||||||
"productVariantService"
|
"productVariantService"
|
||||||
)
|
)
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
|
||||||
|
const createdId: Record<string, string | null> = {
|
||||||
|
variant: null,
|
||||||
|
inventoryItem: null,
|
||||||
|
}
|
||||||
|
|
||||||
const manager: EntityManager = req.scope.resolve("manager")
|
const manager: EntityManager = req.scope.resolve("manager")
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager.transaction(async (transactionManager) => {
|
||||||
return await productVariantService
|
const inventoryServiceTx =
|
||||||
.withTransaction(transactionManager)
|
inventoryService?.withTransaction(transactionManager)
|
||||||
.create(id, validated as CreateProductVariantInput)
|
|
||||||
|
const productVariantInventoryServiceTx =
|
||||||
|
productVariantInventoryService.withTransaction(transactionManager)
|
||||||
|
|
||||||
|
const productVariantServiceTx =
|
||||||
|
productVariantService.withTransaction(transactionManager)
|
||||||
|
|
||||||
|
async function createVariant() {
|
||||||
|
const variant = await productVariantServiceTx.create(
|
||||||
|
id,
|
||||||
|
validated as CreateProductVariantInput
|
||||||
|
)
|
||||||
|
|
||||||
|
createdId.variant = variant.id
|
||||||
|
|
||||||
|
return { variant }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeVariant() {
|
||||||
|
if (createdId.variant) {
|
||||||
|
await productVariantServiceTx.delete(createdId.variant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createInventoryItem(variant) {
|
||||||
|
if (!validated.manage_inventory) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const inventoryItem = await inventoryServiceTx!.createInventoryItem({
|
||||||
|
sku: validated.sku,
|
||||||
|
origin_country: validated.origin_country,
|
||||||
|
hs_code: validated.hs_code,
|
||||||
|
mid_code: validated.mid_code,
|
||||||
|
material: validated.material,
|
||||||
|
weight: validated.weight,
|
||||||
|
length: validated.length,
|
||||||
|
height: validated.height,
|
||||||
|
width: validated.width,
|
||||||
|
})
|
||||||
|
|
||||||
|
createdId.inventoryItem = inventoryItem.id
|
||||||
|
|
||||||
|
return { variant, inventoryItem }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeInventoryItem() {
|
||||||
|
if (createdId.inventoryItem) {
|
||||||
|
await inventoryServiceTx!.deleteInventoryItem(createdId.inventoryItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function attachInventoryItem(variant, inventoryItem) {
|
||||||
|
if (!validated.manage_inventory) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await productVariantInventoryServiceTx.attachInventoryItem(
|
||||||
|
variant.id,
|
||||||
|
inventoryItem.id,
|
||||||
|
validated.inventory_quantity
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transactionHandler(
|
||||||
|
actionId: string,
|
||||||
|
type: TransactionHandlerType,
|
||||||
|
payload: TransactionPayload
|
||||||
|
) {
|
||||||
|
const command = {
|
||||||
|
[actions.createVariant]: {
|
||||||
|
[TransactionHandlerType.INVOKE]: async () => {
|
||||||
|
return await createVariant()
|
||||||
|
},
|
||||||
|
[TransactionHandlerType.COMPENSATE]: async () => {
|
||||||
|
await removeVariant()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[actions.createInventoryItem]: {
|
||||||
|
[TransactionHandlerType.INVOKE]: async (data) => {
|
||||||
|
const { variant } = data._response ?? {}
|
||||||
|
return await createInventoryItem(variant)
|
||||||
|
},
|
||||||
|
[TransactionHandlerType.COMPENSATE]: async () => {
|
||||||
|
await removeInventoryItem()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[actions.attachInventoryItem]: {
|
||||||
|
[TransactionHandlerType.INVOKE]: async (data) => {
|
||||||
|
const { variant, inventoryItem } = data._response ?? {}
|
||||||
|
return await attachInventoryItem(variant, inventoryItem)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return command[actionId][type](payload.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const strategy = inventoryService
|
||||||
|
? createVariantStrategyWithInventory
|
||||||
|
: createSimpleVariantStrategy
|
||||||
|
|
||||||
|
const transaction = await strategy.beginTransaction(
|
||||||
|
ulid(),
|
||||||
|
transactionHandler,
|
||||||
|
validated
|
||||||
|
)
|
||||||
|
await strategy.resume(transaction)
|
||||||
|
|
||||||
|
if (transaction.getState() !== TransactionState.DONE) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
transaction.errors.map((err) => err.error?.message).join("\n")
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
const product = await productService.retrieve(id, {
|
const product = await productService.retrieve(id, {
|
||||||
select: defaultAdminProductFields,
|
select: defaultAdminProductFields,
|
||||||
relations: defaultAdminProductRelations,
|
relations: defaultAdminProductRelations,
|
||||||
@@ -175,6 +355,7 @@ class ProductVariantOptionReq {
|
|||||||
* manage_inventory:
|
* manage_inventory:
|
||||||
* description: Whether Medusa should keep track of the inventory for this Product Variant.
|
* description: Whether Medusa should keep track of the inventory for this Product Variant.
|
||||||
* type: boolean
|
* type: boolean
|
||||||
|
* default: true
|
||||||
* weight:
|
* weight:
|
||||||
* description: The wieght of the Product Variant.
|
* description: The wieght of the Product Variant.
|
||||||
* type: number
|
* type: number
|
||||||
@@ -274,7 +455,7 @@ export class AdminPostProductsProductVariantsReq {
|
|||||||
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
manage_inventory?: boolean
|
manage_inventory?: boolean = true
|
||||||
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { EntityManager } from "typeorm"
|
||||||
import { FindConfig } from "../../types/common"
|
import { FindConfig } from "../../types/common"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -15,6 +16,8 @@ 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>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { EntityManager } from "typeorm"
|
||||||
import { FindConfig } from "../../types/common"
|
import { FindConfig } from "../../types/common"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -8,6 +9,7 @@ import {
|
|||||||
} from "../../types/stock-location"
|
} from "../../types/stock-location"
|
||||||
|
|
||||||
export interface IStockLocationService {
|
export interface IStockLocationService {
|
||||||
|
withTransaction(transactionManager?: EntityManager): this
|
||||||
list(
|
list(
|
||||||
selector: FilterableStockLocationProps,
|
selector: FilterableStockLocationProps,
|
||||||
config?: FindConfig<StockLocationDTO>
|
config?: FindConfig<StockLocationDTO>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ describe("modules loader", () => {
|
|||||||
container = buildContainer()
|
container = buildContainer()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("registers service as false in container when no resolution path is given", async () => {
|
it("registers service as undefined in container when no resolution path is given", async () => {
|
||||||
const moduleResolutions: Record<string, ModuleResolution> = {
|
const moduleResolutions: Record<string, ModuleResolution> = {
|
||||||
testService: {
|
testService: {
|
||||||
resolutionPath: false,
|
resolutionPath: false,
|
||||||
@@ -110,7 +110,7 @@ describe("modules loader", () => {
|
|||||||
const testService = container.resolve(
|
const testService = container.resolve(
|
||||||
moduleResolutions.testService.definition.key
|
moduleResolutions.testService.definition.key
|
||||||
)
|
)
|
||||||
expect(testService).toBe(false)
|
expect(testService).toBe(undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("registers service ", async () => {
|
it("registers service ", async () => {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const registerModule = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
container.register({
|
container.register({
|
||||||
[constainerName]: asValue(false),
|
[constainerName]: asValue(undefined),
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -42,7 +42,7 @@ const registerModule = async (
|
|||||||
|
|
||||||
if (!resolution.resolutionPath) {
|
if (!resolution.resolutionPath) {
|
||||||
container.register({
|
container.register({
|
||||||
[constainerName]: asValue(false),
|
[constainerName]: asValue(undefined),
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -106,11 +106,13 @@ class ProductVariantInventoryService extends TransactionBaseService {
|
|||||||
const hasInventory = await Promise.all(
|
const hasInventory = await Promise.all(
|
||||||
variantInventory.map(async (inventoryPart) => {
|
variantInventory.map(async (inventoryPart) => {
|
||||||
const itemQuantity = inventoryPart.required_quantity * quantity
|
const itemQuantity = inventoryPart.required_quantity * quantity
|
||||||
return await this.inventoryService_.confirmInventory(
|
return await this.inventoryService_
|
||||||
inventoryPart.inventory_item_id,
|
.withTransaction(manager)
|
||||||
locations,
|
.confirmInventory(
|
||||||
itemQuantity
|
inventoryPart.inventory_item_id,
|
||||||
)
|
locations,
|
||||||
|
itemQuantity
|
||||||
|
)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -250,9 +252,11 @@ class ProductVariantInventoryService extends TransactionBaseService {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Verify that item exists
|
// Verify that item exists
|
||||||
await this.inventoryService_.retrieveInventoryItem(inventoryItemId, {
|
await this.inventoryService_
|
||||||
select: ["id"],
|
.withTransaction(manager)
|
||||||
})
|
.retrieveInventoryItem(inventoryItemId, {
|
||||||
|
select: ["id"],
|
||||||
|
})
|
||||||
|
|
||||||
const variantInventoryRepo = manager.getRepository(
|
const variantInventoryRepo = manager.getRepository(
|
||||||
ProductVariantInventoryItem
|
ProductVariantInventoryItem
|
||||||
@@ -374,12 +378,14 @@ class ProductVariantInventoryService extends TransactionBaseService {
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
variantInventory.map(async (inventoryPart) => {
|
variantInventory.map(async (inventoryPart) => {
|
||||||
const itemQuantity = inventoryPart.required_quantity * quantity
|
const itemQuantity = inventoryPart.required_quantity * quantity
|
||||||
return await this.inventoryService_.createReservationItem({
|
return await this.inventoryService_
|
||||||
...toReserve,
|
.withTransaction(manager)
|
||||||
location_id: locationId as string,
|
.createReservationItem({
|
||||||
inventory_item_id: inventoryPart.inventory_item_id,
|
...toReserve,
|
||||||
quantity: itemQuantity,
|
location_id: locationId as string,
|
||||||
})
|
inventory_item_id: inventoryPart.inventory_item_id,
|
||||||
|
quantity: itemQuantity,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -414,8 +420,11 @@ class ProductVariantInventoryService extends TransactionBaseService {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const [reservations, reservationCount] =
|
|
||||||
await this.inventoryService_.listReservationItems(
|
const manager = this.transactionManager_ || this.manager_
|
||||||
|
const [reservations, reservationCount] = await this.inventoryService_
|
||||||
|
.withTransaction(manager)
|
||||||
|
.listReservationItems(
|
||||||
{
|
{
|
||||||
line_item_id: lineItemId,
|
line_item_id: lineItemId,
|
||||||
},
|
},
|
||||||
@@ -442,11 +451,15 @@ class ProductVariantInventoryService extends TransactionBaseService {
|
|||||||
quantity * productVariantInventory.required_quantity
|
quantity * productVariantInventory.required_quantity
|
||||||
|
|
||||||
if (reservationQtyUpdate === 0) {
|
if (reservationQtyUpdate === 0) {
|
||||||
await this.inventoryService_.deleteReservationItem(reservation.id)
|
await this.inventoryService_
|
||||||
|
.withTransaction(manager)
|
||||||
|
.deleteReservationItem(reservation.id)
|
||||||
} else {
|
} else {
|
||||||
await this.inventoryService_.updateReservationItem(reservation.id, {
|
await this.inventoryService_
|
||||||
quantity: reservationQtyUpdate,
|
.withTransaction(manager)
|
||||||
})
|
.updateReservationItem(reservation.id, {
|
||||||
|
quantity: reservationQtyUpdate,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -523,7 +536,10 @@ class ProductVariantInventoryService extends TransactionBaseService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.inventoryService_.deleteReservationItemsByLineItem(lineItemId)
|
const manager = this.transactionManager_ || this.manager_
|
||||||
|
await this.inventoryService_
|
||||||
|
.withTransaction(manager)
|
||||||
|
.deleteReservationItemsByLineItem(lineItemId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -554,6 +570,7 @@ class ProductVariantInventoryService extends TransactionBaseService {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
const manager = this.transactionManager_ || this.manager_
|
||||||
const variantInventory = await this.listByVariant(variantId)
|
const variantInventory = await this.listByVariant(variantId)
|
||||||
|
|
||||||
if (variantInventory.length === 0) {
|
if (variantInventory.length === 0) {
|
||||||
@@ -563,11 +580,13 @@ class ProductVariantInventoryService extends TransactionBaseService {
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
variantInventory.map(async (inventoryPart) => {
|
variantInventory.map(async (inventoryPart) => {
|
||||||
const itemQuantity = inventoryPart.required_quantity * quantity
|
const itemQuantity = inventoryPart.required_quantity * quantity
|
||||||
return await this.inventoryService_.adjustInventory(
|
return await this.inventoryService_
|
||||||
inventoryPart.inventory_item_id,
|
.withTransaction(manager)
|
||||||
locationId,
|
.adjustInventory(
|
||||||
itemQuantity
|
inventoryPart.inventory_item_id,
|
||||||
)
|
locationId,
|
||||||
|
itemQuantity
|
||||||
|
)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user