From aa54d902e595eb8b1ed0a09bf0ee3363157093b5 Mon Sep 17 00:00:00 2001 From: "Carlos R. L. Rodrigues" <37986729+carlos-r-l-rodrigues@users.noreply.github.com> Date: Wed, 18 Jan 2023 09:29:06 -0300 Subject: [PATCH] chore: added missing withTransacton, create-variant using TO (#3047) Create variant integrated with Inventory modules --- integration-tests/development/dev-require.js | 39 ++-- integration-tests/development/server.js | 33 ++- .../1665748086258-inventory_setup.ts | 2 +- packages/inventory/src/services/inventory.ts | 179 +++++++++------- .../products/__tests__/create-variant.js | 1 + .../routes/admin/products/create-variant.ts | 199 +++++++++++++++++- .../src/interfaces/services/inventory.ts | 3 + .../src/interfaces/services/stock-location.ts | 2 + .../src/loaders/__tests__/module.spec.ts | 4 +- packages/medusa/src/loaders/module.ts | 4 +- .../src/services/product-variant-inventory.ts | 71 ++++--- 11 files changed, 409 insertions(+), 128 deletions(-) diff --git a/integration-tests/development/dev-require.js b/integration-tests/development/dev-require.js index b47ffa20ce..19468a44dd 100644 --- a/integration-tests/development/dev-require.js +++ b/integration-tests/development/dev-require.js @@ -1,53 +1,68 @@ if (process.env.NODE_ENV !== "development") { return } - const path = require("path") const Module = require("module") const originalRequire = Module.prototype.require const medusaCore = path.resolve(path.join(__dirname, "../../packages")) -function replacePath(requirePath, package, concatPackage = true) { - const idx = requirePath.indexOf(package) - const packPath = requirePath.substring(idx + package.length) +function replacePath(requirePath, pack, concatPackage = true) { + const idx = requirePath.indexOf(pack) + const packPath = requirePath.substring(idx + pack.length).replace(/\\/g, "/") let newPath = medusaCore + "/" + - (concatPackage ? package + "/" : "") + + (concatPackage ? pack + "/" : "") + packPath.replace("/dist", "/src").replace(".js", "") if (!newPath.includes("/src")) { newPath += "/src" } + return path.resolve(newPath) } -Module.prototype.require = function (...args) { +function checkAndReplacePaths(path) { const interfaces = "medusa-interfaces" const utils = "medusa-core-utils" const base = "@medusajs" - if (args[0].includes(base)) { - args[0] = replacePath(args[0], base, false) - } else if (args[0].includes(interfaces)) { - args[0] = replacePath(args[0], interfaces) - } else if (args[0].includes(utils)) { - args[0] = replacePath(args[0], utils) + if (path.includes(base)) { + path = replacePath(path, base, false) + } else if (path.includes(interfaces)) { + path = replacePath(path, interfaces) + } else if (path.includes(utils)) { + path = replacePath(path, utils) } + return path +} + +Module.prototype.require = function (...args) { + args[0] = checkAndReplacePaths(args[0]) + if (args[0] === "glob") { const glob = originalRequire.apply(this, args) const originalGlobSync = glob.sync glob.GlobSync = glob.sync = (pattern, options) => { if (pattern.endsWith(".js") || pattern.endsWith(".ts")) { + pattern = checkAndReplacePaths(pattern) pattern = pattern.replace(".js", ".{j,t}s").replace("/dist/", "/src/") } return originalGlobSync.apply(this, [pattern, options]) } 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) diff --git a/integration-tests/development/server.js b/integration-tests/development/server.js index 04eccbe235..3cd7be8a21 100644 --- a/integration-tests/development/server.js +++ b/integration-tests/development/server.js @@ -14,6 +14,22 @@ const medusaCore = path .replace(/\\/g, "/") 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 = () => { if (WATCHING) { return @@ -42,7 +58,12 @@ const watchFiles = () => { }) watcher.on("change", async function (rawFile) { + if (IS_RELOADING) { + return + } + console.log("Reloading server...") + IS_RELOADING = true const start = Date.now() const file = rawFile.replace(/\\/g, "/") @@ -75,12 +96,18 @@ const watchFiles = () => { next.endsWith(".ts") || 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() + IS_RELOADING = false console.log("Server reloaded in", Date.now() - start, "ms") }) @@ -119,8 +146,6 @@ const bootstrapApp = async () => { watchFiles() console.log(`Server Running at localhost:${port}`) }) - - database = dbConnection } -bootstrapApp() +void bootstrapApp() diff --git a/packages/inventory/src/migrations/schema-migrations/1665748086258-inventory_setup.ts b/packages/inventory/src/migrations/schema-migrations/1665748086258-inventory_setup.ts index 0608bbcf9d..e5ac73ec03 100644 --- a/packages/inventory/src/migrations/schema-migrations/1665748086258-inventory_setup.ts +++ b/packages/inventory/src/migrations/schema-migrations/1665748086258-inventory_setup.ts @@ -66,7 +66,7 @@ export class inventorySetup1665748086258 implements MigrationInterface { 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" ( diff --git a/packages/inventory/src/services/inventory.ts b/packages/inventory/src/services/inventory.ts index 0afeb18319..6f49d46f47 100644 --- a/packages/inventory/src/services/inventory.ts +++ b/packages/inventory/src/services/inventory.ts @@ -75,6 +75,10 @@ export default class InventoryService }) } + private getManager(): EntityManager { + return this.transactionManager_ ?? this.manager_ + } + /** * Lists inventory items that match the given selector * @param selector - the selector to filter inventory items by @@ -85,7 +89,9 @@ export default class InventoryService selector: FilterableInventoryItemProps, config: FindConfig = { relations: [], skip: 0, take: 10 } ): 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, config: FindConfig = { relations: [], skip: 0, take: 10 } ): 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, } ): 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, config?: FindConfig ): Promise { - const inventoryItem = await this.inventoryItemService_.retrieve( - inventoryItemId, - config - ) + const inventoryItem = await this.inventoryItemService_ + .withTransaction(this.getManager()) + .retrieve(inventoryItemId, config) return { ...inventoryItem } } @@ -145,10 +154,12 @@ export default class InventoryService inventoryItemId: string, locationId: string ): Promise { - const [inventoryLevel] = await this.inventoryLevelService_.list( - { inventory_item_id: inventoryItemId, location_id: locationId }, - { take: 1 } - ) + const [inventoryLevel] = await this.inventoryLevelService_ + .withTransaction(this.getManager()) + .list( + { inventory_item_id: inventoryItemId, location_id: locationId }, + { take: 1 } + ) if (!inventoryLevel) { throw new MedusaError( MedusaError.Types.NOT_FOUND, @@ -167,13 +178,15 @@ export default class InventoryService input: CreateReservationItemInput ): Promise { // Verify that the item is stocked at the location - const [inventoryLevel] = await this.inventoryLevelService_.list( - { - inventory_item_id: input.inventory_item_id, - location_id: input.location_id, - }, - { take: 1 } - ) + const [inventoryLevel] = await this.inventoryLevelService_ + .withTransaction(this.getManager()) + .list( + { + inventory_item_id: input.inventory_item_id, + location_id: input.location_id, + }, + { take: 1 } + ) if (!inventoryLevel) { 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 } } @@ -195,7 +210,9 @@ export default class InventoryService async createInventoryItem( input: CreateInventoryItemInput ): Promise { - const inventoryItem = await this.inventoryItemService_.create(input) + const inventoryItem = await this.inventoryItemService_ + .withTransaction(this.getManager()) + .create(input) return { ...inventoryItem } } @@ -207,7 +224,9 @@ export default class InventoryService async createInventoryLevel( input: CreateInventoryLevelInput ): Promise { - 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, input: Partial ): Promise { - const inventoryItem = await this.inventoryItemService_.update( - inventoryItemId, - input - ) + const inventoryItem = await this.inventoryItemService_ + .withTransaction(this.getManager()) + .update(inventoryItemId, input) return { ...inventoryItem } } @@ -232,7 +250,9 @@ export default class InventoryService * @param inventoryItemId - the id of the inventory item to delete */ async deleteInventoryItem(inventoryItemId: string): Promise { - 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, locationId: string ): Promise { - const [inventoryLevel] = await this.inventoryLevelService_.list( - { inventory_item_id: inventoryItemId, location_id: locationId }, - { take: 1 } - ) + const [inventoryLevel] = await this.inventoryLevelService_ + .withTransaction(this.getManager()) + .list( + { inventory_item_id: inventoryItemId, location_id: locationId }, + { take: 1 } + ) if (!inventoryLevel) { 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, input: UpdateInventoryLevelInput ): Promise { - const [inventoryLevel] = await this.inventoryLevelService_.list( - { inventory_item_id: inventoryItemId, location_id: locationId }, - { take: 1 } - ) + const [inventoryLevel] = await this.inventoryLevelService_ + .withTransaction(this.getManager()) + .list( + { inventory_item_id: inventoryItemId, location_id: locationId }, + { take: 1 } + ) if (!inventoryLevel) { 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, input: UpdateReservationItemInput ): Promise { - 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 */ async deleteReservationItemsByLineItem(lineItemId: string): Promise { - 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 */ async deleteReservationItem(reservationItemId: string): Promise { - 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, adjustment: number ): Promise { - const [inventoryLevel] = await this.inventoryLevelService_.list( - { inventory_item_id: inventoryItemId, location_id: locationId }, - { take: 1 } - ) + const [inventoryLevel] = await this.inventoryLevelService_ + .withTransaction(this.getManager()) + .list( + { inventory_item_id: inventoryItemId, location_id: locationId }, + { take: 1 } + ) if (!inventoryLevel) { throw new MedusaError( MedusaError.Types.NOT_FOUND, @@ -336,12 +372,11 @@ export default class InventoryService ) } - const updatedInventoryLevel = await this.inventoryLevelService_.update( - inventoryLevel.id, - { + const updatedInventoryLevel = await this.inventoryLevelService_ + .withTransaction(this.getManager()) + .update(inventoryLevel.id, { stocked_quantity: inventoryLevel.stocked_quantity + adjustment, - } - ) + }) return { ...updatedInventoryLevel } } @@ -358,15 +393,15 @@ export default class InventoryService locationIds: string[] ): Promise { // Throws if item does not exist - await this.inventoryItemService_.retrieve(inventoryItemId, { - select: ["id"], - }) + await this.inventoryItemService_ + .withTransaction(this.getManager()) + .retrieve(inventoryItemId, { + select: ["id"], + }) - const availableQuantity = - await this.inventoryLevelService_.getAvailableQuantity( - inventoryItemId, - locationIds - ) + const availableQuantity = await this.inventoryLevelService_ + .withTransaction(this.getManager()) + .getAvailableQuantity(inventoryItemId, locationIds) return availableQuantity } @@ -383,15 +418,15 @@ export default class InventoryService locationIds: string[] ): Promise { // Throws if item does not exist - await this.inventoryItemService_.retrieve(inventoryItemId, { - select: ["id"], - }) + await this.inventoryItemService_ + .withTransaction(this.getManager()) + .retrieve(inventoryItemId, { + select: ["id"], + }) - const stockedQuantity = - await this.inventoryLevelService_.getStockedQuantity( - inventoryItemId, - locationIds - ) + const stockedQuantity = await this.inventoryLevelService_ + .withTransaction(this.getManager()) + .getStockedQuantity(inventoryItemId, locationIds) return stockedQuantity } @@ -408,15 +443,15 @@ export default class InventoryService locationIds: string[] ): Promise { // Throws if item does not exist - await this.inventoryItemService_.retrieve(inventoryItemId, { - select: ["id"], - }) + await this.inventoryItemService_ + .withTransaction(this.getManager()) + .retrieve(inventoryItemId, { + select: ["id"], + }) - const reservedQuantity = - await this.inventoryLevelService_.getReservedQuantity( - inventoryItemId, - locationIds - ) + const reservedQuantity = await this.inventoryLevelService_ + .withTransaction(this.getManager()) + .getReservedQuantity(inventoryItemId, locationIds) return reservedQuantity } diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/create-variant.js b/packages/medusa/src/api/routes/admin/products/__tests__/create-variant.js index 6063071ecb..eb4c2c0a7b 100644 --- a/packages/medusa/src/api/routes/admin/products/__tests__/create-variant.js +++ b/packages/medusa/src/api/routes/admin/products/__tests__/create-variant.js @@ -39,6 +39,7 @@ describe("POST /admin/products/:id/variants", () => { IdMap.getId("productWithOptions"), { inventory_quantity: 0, + manage_inventory: true, title: "Test Product Variant", options: [], prices: [ diff --git a/packages/medusa/src/api/routes/admin/products/create-variant.ts b/packages/medusa/src/api/routes/admin/products/create-variant.ts index ccdf464510..3468336101 100644 --- a/packages/medusa/src/api/routes/admin/products/create-variant.ts +++ b/packages/medusa/src/api/routes/admin/products/create-variant.ts @@ -7,17 +7,33 @@ import { IsString, ValidateNested, } from "class-validator" -import { defaultAdminProductFields, defaultAdminProductRelations } from "." -import { ProductService, ProductVariantService } from "../../../../services" - import { Type } from "class-transformer" -import { EntityManager } from "typeorm" +import { + ProductService, + ProductVariantService, + ProductVariantInventoryService, +} from "../../../../services" +import { defaultAdminProductFields, defaultAdminProductRelations } from "." + +import { IInventoryService } from "../../../../interfaces" import { CreateProductVariantInput, ProductVariantPricesCreateReq, } from "../../../../types/product-variant" 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 * operationId: "PostProductsProductVariants" @@ -103,6 +119,48 @@ import { validator } from "../../../../utils/validator" * "500": * $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) => { const { id } = req.params @@ -111,18 +169,140 @@ export default async (req, res) => { req.body ) + const inventoryService: IInventoryService | undefined = + req.scope.resolve("inventoryService") + const productVariantInventoryService: ProductVariantInventoryService = + req.scope.resolve("productVariantInventoryService") const productVariantService: ProductVariantService = req.scope.resolve( "productVariantService" ) - const productService: ProductService = req.scope.resolve("productService") + + const createdId: Record = { + variant: null, + inventoryItem: null, + } const manager: EntityManager = req.scope.resolve("manager") await manager.transaction(async (transactionManager) => { - return await productVariantService - .withTransaction(transactionManager) - .create(id, validated as CreateProductVariantInput) + const inventoryServiceTx = + inventoryService?.withTransaction(transactionManager) + + 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, { select: defaultAdminProductFields, relations: defaultAdminProductRelations, @@ -175,6 +355,7 @@ class ProductVariantOptionReq { * manage_inventory: * description: Whether Medusa should keep track of the inventory for this Product Variant. * type: boolean + * default: true * weight: * description: The wieght of the Product Variant. * type: number @@ -274,7 +455,7 @@ export class AdminPostProductsProductVariantsReq { @IsBoolean() @IsOptional() - manage_inventory?: boolean + manage_inventory?: boolean = true @IsNumber() @IsOptional() diff --git a/packages/medusa/src/interfaces/services/inventory.ts b/packages/medusa/src/interfaces/services/inventory.ts index cfef370338..5e1aa6571c 100644 --- a/packages/medusa/src/interfaces/services/inventory.ts +++ b/packages/medusa/src/interfaces/services/inventory.ts @@ -1,3 +1,4 @@ +import { EntityManager } from "typeorm" import { FindConfig } from "../../types/common" import { @@ -15,6 +16,8 @@ import { } from "../../types/inventory" export interface IInventoryService { + withTransaction(transactionManager?: EntityManager): this + listInventoryItems( selector: FilterableInventoryItemProps, config?: FindConfig diff --git a/packages/medusa/src/interfaces/services/stock-location.ts b/packages/medusa/src/interfaces/services/stock-location.ts index e5e8ef29f0..829ca9cb08 100644 --- a/packages/medusa/src/interfaces/services/stock-location.ts +++ b/packages/medusa/src/interfaces/services/stock-location.ts @@ -1,3 +1,4 @@ +import { EntityManager } from "typeorm" import { FindConfig } from "../../types/common" import { @@ -8,6 +9,7 @@ import { } from "../../types/stock-location" export interface IStockLocationService { + withTransaction(transactionManager?: EntityManager): this list( selector: FilterableStockLocationProps, config?: FindConfig diff --git a/packages/medusa/src/loaders/__tests__/module.spec.ts b/packages/medusa/src/loaders/__tests__/module.spec.ts index f07ba400d9..f117da8316 100644 --- a/packages/medusa/src/loaders/__tests__/module.spec.ts +++ b/packages/medusa/src/loaders/__tests__/module.spec.ts @@ -81,7 +81,7 @@ describe("modules loader", () => { 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 = { testService: { resolutionPath: false, @@ -110,7 +110,7 @@ describe("modules loader", () => { const testService = container.resolve( moduleResolutions.testService.definition.key ) - expect(testService).toBe(false) + expect(testService).toBe(undefined) }) it("registers service ", async () => { diff --git a/packages/medusa/src/loaders/module.ts b/packages/medusa/src/loaders/module.ts index 8c882c1429..f7c4ab8066 100644 --- a/packages/medusa/src/loaders/module.ts +++ b/packages/medusa/src/loaders/module.ts @@ -32,7 +32,7 @@ const registerModule = async ( } container.register({ - [constainerName]: asValue(false), + [constainerName]: asValue(undefined), }) return { @@ -42,7 +42,7 @@ const registerModule = async ( if (!resolution.resolutionPath) { container.register({ - [constainerName]: asValue(false), + [constainerName]: asValue(undefined), }) return diff --git a/packages/medusa/src/services/product-variant-inventory.ts b/packages/medusa/src/services/product-variant-inventory.ts index 72282d4015..8e5da9d4c3 100644 --- a/packages/medusa/src/services/product-variant-inventory.ts +++ b/packages/medusa/src/services/product-variant-inventory.ts @@ -106,11 +106,13 @@ class ProductVariantInventoryService extends TransactionBaseService { const hasInventory = await Promise.all( variantInventory.map(async (inventoryPart) => { const itemQuantity = inventoryPart.required_quantity * quantity - return await this.inventoryService_.confirmInventory( - inventoryPart.inventory_item_id, - locations, - itemQuantity - ) + return await this.inventoryService_ + .withTransaction(manager) + .confirmInventory( + inventoryPart.inventory_item_id, + locations, + itemQuantity + ) }) ) @@ -250,9 +252,11 @@ class ProductVariantInventoryService extends TransactionBaseService { }) // Verify that item exists - await this.inventoryService_.retrieveInventoryItem(inventoryItemId, { - select: ["id"], - }) + await this.inventoryService_ + .withTransaction(manager) + .retrieveInventoryItem(inventoryItemId, { + select: ["id"], + }) const variantInventoryRepo = manager.getRepository( ProductVariantInventoryItem @@ -374,12 +378,14 @@ class ProductVariantInventoryService extends TransactionBaseService { await Promise.all( variantInventory.map(async (inventoryPart) => { const itemQuantity = inventoryPart.required_quantity * quantity - return await this.inventoryService_.createReservationItem({ - ...toReserve, - location_id: locationId as string, - inventory_item_id: inventoryPart.inventory_item_id, - quantity: itemQuantity, - }) + return await this.inventoryService_ + .withTransaction(manager) + .createReservationItem({ + ...toReserve, + 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, }, @@ -442,11 +451,15 @@ class ProductVariantInventoryService extends TransactionBaseService { quantity * productVariantInventory.required_quantity if (reservationQtyUpdate === 0) { - await this.inventoryService_.deleteReservationItem(reservation.id) + await this.inventoryService_ + .withTransaction(manager) + .deleteReservationItem(reservation.id) } else { - await this.inventoryService_.updateReservationItem(reservation.id, { - quantity: reservationQtyUpdate, - }) + await this.inventoryService_ + .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 { + const manager = this.transactionManager_ || this.manager_ const variantInventory = await this.listByVariant(variantId) if (variantInventory.length === 0) { @@ -563,11 +580,13 @@ class ProductVariantInventoryService extends TransactionBaseService { await Promise.all( variantInventory.map(async (inventoryPart) => { const itemQuantity = inventoryPart.required_quantity * quantity - return await this.inventoryService_.adjustInventory( - inventoryPart.inventory_item_id, - locationId, - itemQuantity - ) + return await this.inventoryService_ + .withTransaction(manager) + .adjustInventory( + inventoryPart.inventory_item_id, + locationId, + itemQuantity + ) }) ) }