diff --git a/integration-tests/http/__tests__/inventory/admin/inventory.spec.ts b/integration-tests/http/__tests__/inventory/admin/inventory.spec.ts index 25f5ba58af..0c9e09f31c 100644 --- a/integration-tests/http/__tests__/inventory/admin/inventory.spec.ts +++ b/integration-tests/http/__tests__/inventory/admin/inventory.spec.ts @@ -581,6 +581,79 @@ medusaIntegrationTestRunner({ }) ) }) + + it("should retrieve the inventory item with correct stocked quantity given location levels have been deleted", async () => { + await api.post( + `/admin/inventory-items/${inventoryItem1.id}/location-levels`, + { + location_id: stockLocation1.id, + stocked_quantity: 10, + incoming_quantity: 0, + }, + adminHeaders + ) + + const item = ( + await api.post( + `/admin/inventory-items/${inventoryItem1.id}/location-levels`, + { + location_id: stockLocation2.id, + stocked_quantity: 10, + incoming_quantity: 0, + }, + adminHeaders + ) + ).data.inventory_item + + await api.post( + `/admin/reservations`, + { + line_item_id: "line-item-id-1", + inventory_item_id: inventoryItem1.id, + location_id: stockLocation2.id, + description: "test description", + quantity: 1, + }, + adminHeaders + ) + + const reservation = ( + await api.post( + `/admin/reservations`, + { + line_item_id: "line-item-id-2", + inventory_item_id: inventoryItem1.id, + location_id: stockLocation2.id, + description: "test description 2", + quantity: 1, + }, + adminHeaders + ) + ).data.reservation + + await api.delete( + `/admin/inventory-items/${inventoryItem1.id}/location-levels/${item.location_levels[0].id}`, + adminHeaders + ) + + await api.delete( + `/admin/reservations/${reservation.id}`, + adminHeaders + ) + + const response = await api.get( + `/admin/inventory-items/${inventoryItem1.id}`, + adminHeaders + ) + + expect(response.data.inventory_item).toEqual( + expect.objectContaining({ + id: inventoryItem1.id, + stocked_quantity: 10, + reserved_quantity: 1, + }) + ) + }) it("should throw if inventory item doesn't exist", async () => { const error = await api diff --git a/packages/modules/inventory-next/src/models/inventory-item.ts b/packages/modules/inventory-next/src/models/inventory-item.ts index 805470b71a..f7bdf40ff3 100644 --- a/packages/modules/inventory-next/src/models/inventory-item.ts +++ b/packages/modules/inventory-next/src/models/inventory-item.ts @@ -131,14 +131,14 @@ export class InventoryItem { @Formula( (item) => - `(SELECT SUM(reserved_quantity) FROM inventory_level il WHERE il.inventory_item_id = ${item}.id)`, + `(SELECT SUM(reserved_quantity) FROM inventory_level il WHERE il.inventory_item_id = ${item}.id AND il.deleted_at IS NULL)`, { lazy: true, serializer: Number, hidden: true } ) reserved_quantity: number @Formula( (item) => - `(SELECT SUM(stocked_quantity) FROM inventory_level il WHERE il.inventory_item_id = ${item}.id)`, + `(SELECT SUM(stocked_quantity) FROM inventory_level il WHERE il.inventory_item_id = ${item}.id AND il.deleted_at IS NULL)`, { lazy: true, serializer: Number, hidden: true } ) stocked_quantity: number diff --git a/packages/modules/inventory-next/src/services/inventory-module.ts b/packages/modules/inventory-next/src/services/inventory-module.ts index 1a375baee5..8ac858a443 100644 --- a/packages/modules/inventory-next/src/services/inventory-module.ts +++ b/packages/modules/inventory-next/src/services/inventory-module.ts @@ -6,26 +6,28 @@ import { ModuleJoinerConfig, ModulesSdkTypes, ReservationItemDTO, + RestoreReturn, + SoftDeleteReturn, } from "@medusajs/types" +import { IInventoryService } from "@medusajs/types/dist/inventory" import { - arrayDifference, CommonEvents, EmitEvents, InjectManager, InjectTransactionManager, InventoryEvents, - isDefined, - isString, MedusaContext, MedusaError, MedusaService, + arrayDifference, + isDefined, + isString, partitionArray, promiseAll, } from "@medusajs/utils" import { InventoryItem, InventoryLevel, ReservationItem } from "@models" import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import InventoryLevelService from "./inventory-level" -import { IInventoryService } from "@medusajs/types/dist/inventory" type InjectedDependencies = { baseRepository: DAL.RepositoryService @@ -774,6 +776,48 @@ export default class InventoryModuleService return result } + @InjectTransactionManager("baseRepository_") + // @ts-expect-error + async softDeleteReservationItems( + ids: string | string[], + config?: SoftDeleteReturn, + @MedusaContext() context: Context = {} + ): Promise { + const reservations: InventoryTypes.ReservationItemDTO[] = + await super.listReservationItems({ id: ids }, {}, context) + + const result = await super.softDeleteReservationItems( + { id: ids }, + config, + context + ) + + await this.adjustInventoryLevelsForReservationsDeletion( + reservations, + context + ) + + result + } + + @InjectTransactionManager("baseRepository_") + // @ts-expect-error + async restoreReservationItems( + ids: string | string[], + config?: RestoreReturn, + @MedusaContext() context: Context = {} + ): Promise { + const reservations: InventoryTypes.ReservationItemDTO[] = + await super.listReservationItems({ id: ids }, {}, context) + + await super.restoreReservationItems({ id: ids }, config, context) + + await this.adjustInventoryLevelsForReservationsRestore( + reservations, + context + ) + } + @InjectTransactionManager("baseRepository_") @EmitEvents() async deleteReservationItemByLocationId(