fix(medusa): Fix hanging inventory item migration script (#3624)

This commit is contained in:
Philip Korsholm authored and GitHub committed 2023-03-30 09:29:44 +02:00
1 parent 377b9ce8c2
commit 999aeb116c
6 files changed
+156 -72

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---
fix(medusa): Fix hanging inventory item migration script
@@ -1,15 +1,16 @@
import { AwilixContainer } from "awilix"
import dotenv from "dotenv"
import express from "express"
import { IInventoryService, IStockLocationService } from "@medusajs/types" import { IInventoryService, IStockLocationService } from "@medusajs/types"
import loaders from "../loaders"
import { ProductVariant } from "../models"
import { import {
ProductVariantInventoryService, ProductVariantInventoryService,
ProductVariantService, ProductVariantService,
} from "../services" } from "../services"
import { AwilixContainer } from "awilix"
import { EntityManager } from "typeorm"
import { ProductVariant } from "../models"
import dotenv from "dotenv"
import express from "express"
import loaders from "../loaders"
dotenv.config() dotenv.config()
const BATCH_SIZE = 100 const BATCH_SIZE = 100
@@ -17,10 +18,24 @@ const BATCH_SIZE = 100
const migrateProductVariant = async ( const migrateProductVariant = async (
variant: ProductVariant, variant: ProductVariant,
locationId: string, locationId: string,
{ container }: { container: AwilixContainer } {
container,
transactionManager,
}: { container: AwilixContainer; transactionManager: EntityManager }
) => { ) => {
const productVariantInventoryService: ProductVariantInventoryService = const productVariantInventoryService: ProductVariantInventoryService =
container.resolve("productVariantInventoryService") container.resolve("productVariantInventoryService")
const productVariantInventoryServiceTx =
productVariantInventoryService.withTransaction(transactionManager)
const existingVariantInventoryItems =
await productVariantInventoryServiceTx.listByVariant(variant.id)
if (existingVariantInventoryItems.length) {
return
}
const inventoryService: IInventoryService = const inventoryService: IInventoryService =
container.resolve("inventoryService") container.resolve("inventoryService")
@@ -28,31 +43,38 @@ const migrateProductVariant = async (
return return
} }
const inventoryItem = await inventoryService.createInventoryItem({ const context = { transactionManager }
sku: variant.sku, const inventoryItem = await inventoryService.createInventoryItem(
material: variant.material, {
width: variant.width, sku: variant.sku,
length: variant.length, material: variant.material,
height: variant.height, width: variant.width,
weight: variant.weight, length: variant.length,
origin_country: variant.origin_country, height: variant.height,
hs_code: variant.hs_code, weight: variant.weight,
mid_code: variant.mid_code, origin_country: variant.origin_country,
requires_shipping: true, hs_code: variant.hs_code,
}) mid_code: variant.mid_code,
requires_shipping: true,
},
context
)
await productVariantInventoryService.attachInventoryItem( await productVariantInventoryServiceTx.attachInventoryItem(
variant.id, variant.id,
inventoryItem.id, inventoryItem.id,
1 1
) )
await inventoryService.createInventoryLevel({ await inventoryService.createInventoryLevel(
location_id: locationId, {
inventory_item_id: inventoryItem.id, location_id: locationId,
stocked_quantity: variant.inventory_quantity, inventory_item_id: inventoryItem.id,
incoming_quantity: 0, stocked_quantity: variant.inventory_quantity,
}) incoming_quantity: 0,
},
context
)
} }
const migrateStockLocation = async (container: AwilixContainer) => { const migrateStockLocation = async (container: AwilixContainer) => {
@@ -75,11 +97,17 @@ const processBatch = async (
locationId: string, locationId: string,
container: AwilixContainer container: AwilixContainer
) => { ) => {
await Promise.all( const manager = container.resolve("manager")
variants.map(async (variant) => { return await manager.transaction(async (transactionManager) => {
await migrateProductVariant(variant, locationId, { container }) await Promise.all(
}) variants.map(async (variant) => {
) await migrateProductVariant(variant, locationId, {
container,
transactionManager,
})
})
)
})
} }
const migrate = async function ({ directory }) { const migrate = async function ({ directory }) {
@@ -247,9 +247,13 @@ class ProductVariantInventoryService extends TransactionBaseService {
}) })
// Verify that item exists // Verify that item exists
await this.inventoryService_.retrieveInventoryItem(inventoryItemId, { await this.inventoryService_.retrieveInventoryItem(
select: ["id"], inventoryItemId,
}) {
select: ["id"],
},
{ transactionManager: this.activeManager_ }
)
const variantInventoryRepo = this.activeManager_.getRepository( const variantInventoryRepo = this.activeManager_.getRepository(
ProductVariantInventoryItem ProductVariantInventoryItem
+5 -6
View File
@@ -1,10 +1,11 @@
import { EventBusTypes } from "@medusajs/types"
import { DeepPartial, EntityManager, In } from "typeorm" import { DeepPartial, EntityManager, In } from "typeorm"
import { EventBusTypes } from "@medusajs/types"
import { FindConfig } from "../types/common"
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity"
import { TransactionBaseService } from "../interfaces"
import { StagedJob } from "../models" import { StagedJob } from "../models"
import { StagedJobRepository } from "../repositories/staged-job" import { StagedJobRepository } from "../repositories/staged-job"
import { FindConfig } from "../types/common" import { TransactionBaseService } from "../interfaces"
import { isString } from "../utils" import { isString } from "../utils"
type StagedJobServiceProps = { type StagedJobServiceProps = {
@@ -42,8 +43,7 @@ class StagedJobService extends TransactionBaseService {
} }
async create(data: EventBusTypes.EmitData[] | EventBusTypes.EmitData) { async create(data: EventBusTypes.EmitData[] | EventBusTypes.EmitData) {
return await this.atomicPhase_(async (manager) => { const stagedJobRepo = this.activeManager_.withRepository(this.stagedJobRepository_)
const stagedJobRepo = manager.withRepository(this.stagedJobRepository_)
const data_ = Array.isArray(data) ? data : [data] const data_ = Array.isArray(data) ? data : [data]
@@ -56,7 +56,6 @@ class StagedJobService extends TransactionBaseService {
) as QueryDeepPartialEntity<StagedJob>[] ) as QueryDeepPartialEntity<StagedJob>[]
return await stagedJobRepo.insertBulk(stagedJobs) return await stagedJobRepo.insertBulk(stagedJobs)
})
} }
} }
+61 -25
View File
@@ -1,5 +1,3 @@
import { FindConfig } from "../common"
import { import {
CreateInventoryItemInput, CreateInventoryItemInput,
CreateInventoryLevelInput, CreateInventoryLevelInput,
@@ -14,101 +12,139 @@ import {
UpdateReservationItemInput, UpdateReservationItemInput,
} from "./common" } from "./common"
import { FindConfig } from "../common"
import { SharedContext } from ".."
export interface IInventoryService { export interface IInventoryService {
listInventoryItems( listInventoryItems(
selector: FilterableInventoryItemProps, selector: FilterableInventoryItemProps,
config?: FindConfig<InventoryItemDTO> config?: FindConfig<InventoryItemDTO>,
context?: SharedContext
): Promise<[InventoryItemDTO[], number]> ): Promise<[InventoryItemDTO[], number]>
listReservationItems( listReservationItems(
selector: FilterableReservationItemProps, selector: FilterableReservationItemProps,
config?: FindConfig<ReservationItemDTO> config?: FindConfig<ReservationItemDTO>,
context?: SharedContext
): Promise<[ReservationItemDTO[], number]> ): Promise<[ReservationItemDTO[], number]>
listInventoryLevels( listInventoryLevels(
selector: FilterableInventoryLevelProps, selector: FilterableInventoryLevelProps,
config?: FindConfig<InventoryLevelDTO> config?: FindConfig<InventoryLevelDTO>,
context?: SharedContext
): Promise<[InventoryLevelDTO[], number]> ): Promise<[InventoryLevelDTO[], number]>
retrieveInventoryItem( retrieveInventoryItem(
inventoryItemId: string, inventoryItemId: string,
config?: FindConfig<InventoryItemDTO> config?: FindConfig<InventoryItemDTO>,
context?: SharedContext
): Promise<InventoryItemDTO> ): Promise<InventoryItemDTO>
retrieveInventoryLevel( retrieveInventoryLevel(
inventoryItemId: string, inventoryItemId: string,
locationId: string locationId: string,
context?: SharedContext
): Promise<InventoryLevelDTO> ): Promise<InventoryLevelDTO>
retrieveReservationItem(reservationId: string): Promise<ReservationItemDTO> retrieveReservationItem(
reservationId: string,
context?: SharedContext
): Promise<ReservationItemDTO>
createReservationItem( createReservationItem(
input: CreateReservationItemInput input: CreateReservationItemInput,
context?: SharedContext
): Promise<ReservationItemDTO> ): Promise<ReservationItemDTO>
createInventoryItem( createInventoryItem(
input: CreateInventoryItemInput input: CreateInventoryItemInput,
context?: SharedContext
): Promise<InventoryItemDTO> ): Promise<InventoryItemDTO>
createInventoryLevel( createInventoryLevel(
data: CreateInventoryLevelInput data: CreateInventoryLevelInput,
context?: SharedContext
): Promise<InventoryLevelDTO> ): Promise<InventoryLevelDTO>
updateInventoryLevel( updateInventoryLevel(
inventoryItemId: string, inventoryItemId: string,
locationId: string, locationId: string,
update: UpdateInventoryLevelInput update: UpdateInventoryLevelInput,
context?: SharedContext
): Promise<InventoryLevelDTO> ): Promise<InventoryLevelDTO>
updateInventoryItem( updateInventoryItem(
inventoryItemId: string, inventoryItemId: string,
input: CreateInventoryItemInput input: CreateInventoryItemInput,
context?: SharedContext
): Promise<InventoryItemDTO> ): Promise<InventoryItemDTO>
updateReservationItem( updateReservationItem(
reservationItemId: string, reservationItemId: string,
input: UpdateReservationItemInput input: UpdateReservationItemInput,
context?: SharedContext
): Promise<ReservationItemDTO> ): Promise<ReservationItemDTO>
deleteReservationItemsByLineItem(lineItemId: string): Promise<void> deleteReservationItemsByLineItem(
lineItemId: string,
context?: SharedContext
): Promise<void>
deleteReservationItem(reservationItemId: string | string[]): Promise<void> deleteReservationItem(
reservationItemId: string | string[],
context?: SharedContext
): Promise<void>
deleteInventoryItem(inventoryItemId: string): Promise<void> deleteInventoryItem(
inventoryItemId: string,
context?: SharedContext
): Promise<void>
deleteInventoryItemLevelByLocationId(locationId: string): Promise<void> deleteInventoryItemLevelByLocationId(
locationId: string,
context?: SharedContext
): Promise<void>
deleteReservationItemByLocationId(locationId: string): Promise<void> deleteReservationItemByLocationId(
locationId: string,
context?: SharedContext
): Promise<void>
deleteInventoryLevel( deleteInventoryLevel(
inventoryLevelId: string, inventoryLevelId: string,
locationId: string locationId: string,
context?: SharedContext
): Promise<void> ): Promise<void>
adjustInventory( adjustInventory(
inventoryItemId: string, inventoryItemId: string,
locationId: string, locationId: string,
adjustment: number adjustment: number,
context?: SharedContext
): Promise<InventoryLevelDTO> ): Promise<InventoryLevelDTO>
confirmInventory( confirmInventory(
inventoryItemId: string, inventoryItemId: string,
locationIds: string[], locationIds: string[],
quantity: number quantity: number,
context?: SharedContext
): Promise<boolean> ): Promise<boolean>
retrieveAvailableQuantity( retrieveAvailableQuantity(
inventoryItemId: string, inventoryItemId: string,
locationIds: string[] locationIds: string[],
context?: SharedContext
): Promise<number> ): Promise<number>
retrieveStockedQuantity( retrieveStockedQuantity(
inventoryItemId: string, inventoryItemId: string,
locationIds: string[] locationIds: string[],
context?: SharedContext
): Promise<number> ): Promise<number>
retrieveReservedQuantity( retrieveReservedQuantity(
inventoryItemId: string, inventoryItemId: string,
locationIds: string[] locationIds: string[],
context?: SharedContext
): Promise<number> ): Promise<number>
} }
@@ -1,4 +1,3 @@
import { FindConfig } from "../common/common"
import { import {
CreateStockLocationInput, CreateStockLocationInput,
FilterableStockLocationProps, FilterableStockLocationProps,
@@ -6,25 +5,38 @@ import {
UpdateStockLocationInput, UpdateStockLocationInput,
} from "./common" } from "./common"
import { FindConfig } from "../common/common"
import { SharedContext } from "../shared-context"
export interface IStockLocationService { export interface IStockLocationService {
list( list(
selector: FilterableStockLocationProps, selector: FilterableStockLocationProps,
config?: FindConfig<StockLocationDTO> config?: FindConfig<StockLocationDTO>,
context?: SharedContext
): Promise<StockLocationDTO[]> ): Promise<StockLocationDTO[]>
listAndCount( listAndCount(
selector: FilterableStockLocationProps, selector: FilterableStockLocationProps,
config?: FindConfig<StockLocationDTO> config?: FindConfig<StockLocationDTO>,
context?: SharedContext
): Promise<[StockLocationDTO[], number]> ): Promise<[StockLocationDTO[], number]>
retrieve( retrieve(
id: string, id: string,
config?: FindConfig<StockLocationDTO> config?: FindConfig<StockLocationDTO>,
context?: SharedContext
): Promise<StockLocationDTO> ): Promise<StockLocationDTO>
create(input: CreateStockLocationInput): Promise<StockLocationDTO> create(
input: CreateStockLocationInput,
context?: SharedContext
): Promise<StockLocationDTO>
update(id: string, input: UpdateStockLocationInput): Promise<StockLocationDTO> update(
id: string,
input: UpdateStockLocationInput,
context?: SharedContext
): Promise<StockLocationDTO>
delete(id: string): Promise<void> delete(id: string, context?: SharedContext): Promise<void>
} }