feat: move create inventory to @medusajs/workflows (#5301)
**Why** - We have some workflow-like flows in @medusajs/medusa. These should be moved over to the workflows package. - Inventory Items <> Variant currently assume a 1-1 mapping. There should be support for a many-to-many mapping. **What** - PR introduces a feature flag for supporting many-to-many mappings for inventory and variants. - Deletes legacy transaction handler in @medusajs/medusa. - Adjusts existing createInventoryItems handler to remove dependency on variant data. **Unkowns** ~~1. Couldn't find an existing test for the CreateProduct workflow. It should be tested that this still works as expected.~~ 2. Have removed transaction managers as we should move to handling consistency through orchestration tooling. Are we ready for that?
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
export * from "./cart"
|
||||
export * from "./product"
|
||||
export * from "./inventory"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { Workflows } from "../../definitions"
|
||||
import {
|
||||
TransactionStepsDefinition,
|
||||
WorkflowManager,
|
||||
} from "@medusajs/orchestration"
|
||||
import { exportWorkflow, pipe } from "../../helper"
|
||||
|
||||
import { InventoryTypes, WorkflowTypes } from "@medusajs/types"
|
||||
import { InventoryHandlers } from "../../handlers"
|
||||
|
||||
export enum CreateInventoryItemActions {
|
||||
prepare = "prepare",
|
||||
createInventoryItems = "createInventoryItems",
|
||||
}
|
||||
|
||||
const workflowSteps: TransactionStepsDefinition = {
|
||||
next: {
|
||||
action: CreateInventoryItemActions.createInventoryItems,
|
||||
},
|
||||
}
|
||||
|
||||
const handlers = new Map([
|
||||
[
|
||||
CreateInventoryItemActions.createInventoryItems,
|
||||
{
|
||||
invoke: pipe(
|
||||
{
|
||||
inputAlias: CreateInventoryItemActions.prepare,
|
||||
merge: true,
|
||||
invoke: {
|
||||
from: CreateInventoryItemActions.prepare,
|
||||
},
|
||||
},
|
||||
InventoryHandlers.createInventoryItems
|
||||
),
|
||||
compensate: pipe(
|
||||
{
|
||||
merge: true,
|
||||
invoke: {
|
||||
from: CreateInventoryItemActions.createInventoryItems,
|
||||
alias:
|
||||
InventoryHandlers.removeInventoryItems.aliases.inventoryItems,
|
||||
},
|
||||
},
|
||||
InventoryHandlers.removeInventoryItems
|
||||
),
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
WorkflowManager.register(
|
||||
Workflows.CreateInventoryItems,
|
||||
workflowSteps,
|
||||
handlers
|
||||
)
|
||||
|
||||
export const createInventoryItems = exportWorkflow<
|
||||
WorkflowTypes.InventoryWorkflow.CreateInventoryItemsWorkflowInputDTO,
|
||||
{ tag: string; inventoryItem: InventoryTypes.InventoryItemDTO }[]
|
||||
>(
|
||||
Workflows.CreateInventoryItems,
|
||||
CreateInventoryItemActions.createInventoryItems,
|
||||
async (data) => data
|
||||
)
|
||||
1
packages/workflows/src/definition/inventory/index.ts
Normal file
1
packages/workflows/src/definition/inventory/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./create-inventory-item"
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
MiddlewaresHandlers,
|
||||
ProductHandlers,
|
||||
} from "../../handlers"
|
||||
import { prepareCreateInventoryItems } from "./prepare-create-inventory-items"
|
||||
|
||||
export enum CreateProductsActions {
|
||||
prepare = "prepare",
|
||||
@@ -175,9 +176,10 @@ const handlers = new Map([
|
||||
merge: true,
|
||||
invoke: {
|
||||
from: CreateProductsActions.createProducts,
|
||||
alias: InventoryHandlers.createInventoryItems.aliases.products,
|
||||
alias: prepareCreateInventoryItems.aliases.products,
|
||||
},
|
||||
},
|
||||
prepareCreateInventoryItems,
|
||||
InventoryHandlers.createInventoryItems
|
||||
),
|
||||
compensate: pipe(
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type AssociationTaggedVariant = ProductTypes.ProductVariantDTO & {
|
||||
_associationTag?: string
|
||||
}
|
||||
|
||||
type ObjectWithVariant = { variants: ProductTypes.ProductVariantDTO[] }
|
||||
|
||||
export async function prepareCreateInventoryItems({
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
products: ObjectWithVariant[]
|
||||
}>) {
|
||||
const taggedVariants = data.products.reduce<AssociationTaggedVariant[]>(
|
||||
(acc, product: ObjectWithVariant) => {
|
||||
const cleanVariants = product.variants.reduce<AssociationTaggedVariant[]>(
|
||||
(acc, variant: AssociationTaggedVariant) => {
|
||||
if (!variant.manage_inventory) {
|
||||
return acc
|
||||
}
|
||||
|
||||
variant._associationTag = variant.id
|
||||
|
||||
acc.push(variant)
|
||||
return acc
|
||||
},
|
||||
[]
|
||||
)
|
||||
return acc.concat(cleanVariants)
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
return {
|
||||
alias: prepareCreateInventoryItems.aliases.output,
|
||||
value: {
|
||||
inventoryItems: taggedVariants,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
prepareCreateInventoryItems.aliases = {
|
||||
products: "products",
|
||||
output: "prepareCreateInventoryItemsOutput",
|
||||
}
|
||||
@@ -4,6 +4,8 @@ export enum Workflows {
|
||||
|
||||
// Cart workflows
|
||||
CreateCart = "create-cart",
|
||||
|
||||
CreateInventoryItems = "create-inventory-items",
|
||||
}
|
||||
|
||||
export enum InputAlias {
|
||||
@@ -16,4 +18,6 @@ export enum InputAlias {
|
||||
|
||||
AttachedInventoryItems = "attachedInventoryItems",
|
||||
DetachedInventoryItems = "detachedInventoryItems",
|
||||
|
||||
InventoryItemsInputData = "inventoryItemsInputData",
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { InventoryItemDTO, ProductTypes } from "@medusajs/types"
|
||||
import { InventoryItemDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
export async function attachInventoryItems({
|
||||
@@ -7,12 +7,11 @@ export async function attachInventoryItems({
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
inventoryItems: {
|
||||
variant: ProductTypes.ProductVariantDTO
|
||||
tag: string
|
||||
inventoryItem: InventoryItemDTO
|
||||
}[]
|
||||
}>) {
|
||||
const { manager } = context
|
||||
|
||||
const productVariantInventoryService = container
|
||||
.resolve("productVariantInventoryService")
|
||||
.withTransaction(manager)
|
||||
@@ -21,12 +20,10 @@ export async function attachInventoryItems({
|
||||
return
|
||||
}
|
||||
|
||||
const inventoryData = data.inventoryItems.map(
|
||||
({ variant, inventoryItem }) => ({
|
||||
variantId: variant.id,
|
||||
inventoryItemId: inventoryItem.id,
|
||||
})
|
||||
)
|
||||
const inventoryData = data.inventoryItems.map(({ tag, inventoryItem }) => ({
|
||||
variantId: tag,
|
||||
inventoryItemId: inventoryItem.id,
|
||||
}))
|
||||
|
||||
return await productVariantInventoryService.attachInventoryItem(inventoryData)
|
||||
}
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
import {
|
||||
IInventoryService,
|
||||
InventoryItemDTO,
|
||||
ProductTypes,
|
||||
} from "@medusajs/types"
|
||||
import { IInventoryService, InventoryItemDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type Result = {
|
||||
variant: ProductTypes.ProductVariantDTO
|
||||
tag: string
|
||||
inventoryItem: InventoryItemDTO
|
||||
}[]
|
||||
|
||||
export async function createInventoryItems({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
products: ProductTypes.ProductDTO[]
|
||||
inventoryItems: (InventoryItemDTO & { _associationTag?: string })[]
|
||||
}>): Promise<Result | void> {
|
||||
const inventoryService: IInventoryService =
|
||||
container.resolve("inventoryService")
|
||||
@@ -28,47 +23,27 @@ export async function createInventoryItems({
|
||||
return void 0
|
||||
}
|
||||
|
||||
const variants = data.products.reduce(
|
||||
(
|
||||
acc: ProductTypes.ProductVariantDTO[],
|
||||
product: ProductTypes.ProductDTO
|
||||
) => {
|
||||
return acc.concat(product.variants)
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const result = await Promise.all(
|
||||
variants.map(async (variant) => {
|
||||
if (!variant.manage_inventory) {
|
||||
return
|
||||
}
|
||||
data.inventoryItems.map(async (item) => {
|
||||
const inventoryItem = await inventoryService!.createInventoryItem({
|
||||
sku: item.sku!,
|
||||
origin_country: item.origin_country!,
|
||||
hs_code: item.hs_code!,
|
||||
mid_code: item.mid_code!,
|
||||
material: item.material!,
|
||||
weight: item.weight!,
|
||||
length: item.length!,
|
||||
height: item.height!,
|
||||
width: item.width!,
|
||||
})
|
||||
|
||||
const inventoryItem = await inventoryService!.createInventoryItem(
|
||||
{
|
||||
sku: variant.sku!,
|
||||
origin_country: variant.origin_country!,
|
||||
hs_code: variant.hs_code!,
|
||||
mid_code: variant.mid_code!,
|
||||
material: variant.material!,
|
||||
weight: variant.weight!,
|
||||
length: variant.length!,
|
||||
height: variant.height!,
|
||||
width: variant.width!,
|
||||
},
|
||||
{
|
||||
transactionManager: (context.transactionManager ??
|
||||
context.manager) as any,
|
||||
}
|
||||
)
|
||||
|
||||
return { variant, inventoryItem }
|
||||
return { tag: item._associationTag ?? inventoryItem.id, inventoryItem }
|
||||
})
|
||||
)
|
||||
|
||||
return result.filter(Boolean) as Result
|
||||
return result
|
||||
}
|
||||
|
||||
createInventoryItems.aliases = {
|
||||
products: "products",
|
||||
payload: "payload",
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { InventoryItemDTO, ProductTypes } from "@medusajs/types"
|
||||
import { InventoryItemDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
export async function detachInventoryItems({
|
||||
@@ -7,7 +7,7 @@ export async function detachInventoryItems({
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
inventoryItems: {
|
||||
variant: ProductTypes.ProductVariantDTO
|
||||
tag: string
|
||||
inventoryItem: InventoryItemDTO
|
||||
}[]
|
||||
}>): Promise<void> {
|
||||
@@ -22,10 +22,10 @@ export async function detachInventoryItems({
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
data.inventoryItems.map(async ({ variant, inventoryItem }) => {
|
||||
data.inventoryItems.map(async ({ tag, inventoryItem }) => {
|
||||
return await productVariantInventoryService.detachInventoryItem(
|
||||
inventoryItem.id,
|
||||
variant.id
|
||||
tag
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
@@ -3,12 +3,10 @@ import { WorkflowArguments } from "../../helper"
|
||||
|
||||
export async function removeInventoryItems({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
inventoryItems: { inventoryItem: InventoryItemDTO }[]
|
||||
}>) {
|
||||
const { manager } = context
|
||||
const inventoryService = container.resolve("inventoryService")
|
||||
|
||||
if (!inventoryService) {
|
||||
@@ -20,8 +18,7 @@ export async function removeInventoryItems({
|
||||
}
|
||||
|
||||
return await inventoryService!.deleteInventoryItem(
|
||||
data.inventoryItems.map(({ inventoryItem }) => inventoryItem.id),
|
||||
{ transactionManager: manager }
|
||||
data.inventoryItems.map(({ inventoryItem }) => inventoryItem.id)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user