test(): Test the create product workflow compensation (#4716)

**What**
Integration tests to validate the workflow compensation.
Also, fix the transaction state when the workflow is compensating and some steps does not have any compensation
This commit is contained in:
Adrien de Peretti authored and GitHub committed 2023-08-09 14:33:04 +00:00
1 parent 86c314eb2a
commit ac866ebb51
21 files changed
+391 -193

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
---
"@medusajs/orchestration": patch
"@medusajs/workflows": patch
"@medusajs/types": patch
"@medusajs/medusa": patch
---
test(): Test the create product workflow compensation
fix(orchestration): Fix the transaction state after compensating with no compensation steps in the middle
chore(workflows): Export and naming
feat(types): Update product workflow input types
feat(medusa): Update product workflow usage and cleanup endpoint
+1 -1
View File
@@ -5,7 +5,7 @@
"license": "MIT", "license": "MIT",
"private": true, "private": true,
"scripts": { "scripts": {
"test:integration": "jest --silent=false --runInBand --bail --detectOpenHandles --forceExit", "test:integration": "jest --silent=false --maxWorkers=50% --bail --detectOpenHandles --forceExit",
"build": "babel src -d dist --extensions \".ts,.js\"" "build": "babel src -d dist --extensions \".ts,.js\""
}, },
"dependencies": { "dependencies": {
@@ -0,0 +1,134 @@
import path from "path"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { bootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import {
createProducts,
CreateProductsActions,
Handlers,
pipe,
} from "@medusajs/workflows"
import { IProductModuleService, WorkflowTypes } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
describe("CreateProduct workflow", function () {
let medusaProcess
let medusaContainer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
await initDb({ cwd } as any)
const { container } = await bootstrapApp({ cwd })
medusaContainer = container
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
medusaProcess.kill()
})
it("should compensate all the invoke if something fails", async () => {
const workflow = createProducts(medusaContainer)
workflow.appendAction(
"fail_step",
CreateProductsActions.attachInventoryItems,
{
invoke: pipe({}, async function failStep() {
throw new Error(`Failed to create products`)
}),
},
{
noCompensation: true,
}
)
const input: WorkflowTypes.ProductWorkflow.CreateProductsWorkflowInputDTO =
{
products: [
{
title: "Test product",
type: { value: "physical" },
tags: [{ value: "test" }],
subtitle: "Test subtitle",
variants: [
{
title: "Test variant",
prices: [
{
amount: 100,
currency_code: "usd",
},
],
},
],
options: [
{
title: "Test option",
},
],
},
],
}
const manager = medusaContainer.resolve("manager")
const context = {
manager,
}
const { result, errors, transaction } = await workflow.run({
input,
context,
throwOnError: false,
})
expect(errors).toEqual([
{
action: "fail_step",
handlerType: "invoke",
error: new Error(`Failed to create products`),
},
])
expect(transaction.getState()).toEqual("reverted")
expect(result).toHaveLength(1)
expect(result[0]).toEqual(
expect.objectContaining({
id: expect.any(String),
})
)
const productId = result[0].id
let [product] = await Handlers.ProductHandlers.listProducts({
container: medusaContainer,
context,
data: {
ids: [productId],
},
} as any)
expect(product).toBeUndefined()
const productModule = medusaContainer.resolve(
ModuleRegistrationName.PRODUCT
) as IProductModuleService
;[product] = await productModule.list(
{
id: productId,
},
{
withDeleted: true,
}
)
expect(product).toEqual(
expect.objectContaining({
deleted_at: expect.any(String),
})
)
})
})
+1
View File
@@ -1,6 +1,7 @@
module.exports = { module.exports = {
globals: { globals: {
"ts-jest": { "ts-jest": {
tsconfig: "tsconfig.spec.json",
diagnostics: false, diagnostics: false,
isolatedModules: true, isolatedModules: true,
}, },
+4
View File
@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"include": ["test"],
}
+1 -1
View File
@@ -40,7 +40,7 @@
"prepare": "cross-env NODE_ENV=production yarn run build", "prepare": "cross-env NODE_ENV=production yarn run build",
"build": "rimraf dist && tsc --build", "build": "rimraf dist && tsc --build",
"serve": "node dist/app.js", "serve": "node dist/app.js",
"test": "jest" "test": "jest --maxWorkers=50% --detectOpenHandles --forceExit"
}, },
"peerDependencies": { "peerDependencies": {
"medusa-interfaces": "^1.3.7", "medusa-interfaces": "^1.3.7",
@@ -2,6 +2,7 @@ import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request" import { request } from "../../../../../helpers/test-request"
import { PriceListServiceMock } from "../../../../../services/__mocks__/price-list" import { PriceListServiceMock } from "../../../../../services/__mocks__/price-list"
jest.setTimeout(10000)
describe("POST /price-lists", () => { describe("POST /price-lists", () => {
describe("successfully creates a price list", () => { describe("successfully creates a price list", () => {
let subject let subject
@@ -35,7 +35,7 @@ import {
import { DistributedTransaction } from "@medusajs/orchestration" import { DistributedTransaction } from "@medusajs/orchestration"
import { IInventoryService, WorkflowTypes } from "@medusajs/types" import { IInventoryService, WorkflowTypes } from "@medusajs/types"
import { FlagRouter } from "@medusajs/utils" import { FlagRouter } from "@medusajs/utils"
import { Workflows, createProducts } from "@medusajs/workflows" import { createProducts, Workflows } from "@medusajs/workflows"
import { Type } from "class-transformer" import { Type } from "class-transformer"
import { EntityManager } from "typeorm" import { EntityManager } from "typeorm"
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
@@ -142,6 +142,8 @@ export default async (req, res) => {
) )
} }
let product
if (isWorkflowEnabled && !!productModuleService) { if (isWorkflowEnabled && !!productModuleService) {
const createProductWorkflow = createProducts(req.scope) const createProductWorkflow = createProducts(req.scope)
@@ -157,119 +159,114 @@ export default async (req, res) => {
}, },
} }
const { result: products } = await createProductWorkflow.run({ const { result } = await createProductWorkflow.run({
input, input,
context: { context: {
manager: entityManager, manager: entityManager,
}, },
}) })
product = result[0]
} else {
product = await entityManager.transaction(async (manager) => {
const { variants } = validated
delete validated.variants
return res.json({ product: products[0] }) if (!validated.thumbnail && validated.images && validated.images.length) {
validated.thumbnail = validated.images[0]
}
let shippingProfile
// Get default shipping profile
if (validated.is_giftcard) {
shippingProfile = await shippingProfileService
.withTransaction(manager)
.retrieveGiftCardDefault()
} else {
shippingProfile = await shippingProfileService
.withTransaction(manager)
.retrieveDefault()
}
// Provided that the feature flag is enabled and
// no sales channels are available, set the default one
if (
featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key) &&
!validated?.sales_channels?.length
) {
const defaultSalesChannel = await salesChannelService
.withTransaction(manager)
.retrieveDefault()
validated.sales_channels = [defaultSalesChannel]
}
const newProduct = await productService
.withTransaction(manager)
.create({ ...validated, profile_id: shippingProfile.id })
if (variants) {
for (const [index, variant] of variants.entries()) {
variant["variant_rank"] = index
}
const optionIds =
validated?.options?.map(
(o) => newProduct.options.find((newO) => newO.title === o.title)?.id
) || []
const allVariantTransactions: DistributedTransaction[] = []
const transactionDependencies = {
manager,
inventoryService,
productVariantInventoryService,
productVariantService,
}
try {
const variantsInputData = variants.map((variant) => {
const options =
variant?.options?.map((option, index) => ({
...option,
option_id: optionIds[index],
})) || []
return {
...variant,
options,
} as CreateProductVariantInput
})
const varTransaction = await createVariantsTransaction(
transactionDependencies,
newProduct.id,
variantsInputData
)
allVariantTransactions.push(varTransaction)
} catch (e) {
await Promise.all(
allVariantTransactions.map(async (transaction) => {
await revertVariantTransaction(
transactionDependencies,
transaction
).catch(() => logger.warn("Transaction couldn't be reverted."))
})
)
throw e
}
}
return newProduct
})
} }
const product = await entityManager.transaction(async (manager) => { const rawProduct = await productService.retrieve(product.id, {
const { variants } = validated select: defaultAdminProductFields,
delete validated.variants relations: defaultAdminProductRelations,
if (!validated.thumbnail && validated.images && validated.images.length) {
validated.thumbnail = validated.images[0]
}
let shippingProfile
// Get default shipping profile
if (validated.is_giftcard) {
shippingProfile = await shippingProfileService
.withTransaction(manager)
.retrieveGiftCardDefault()
} else {
shippingProfile = await shippingProfileService
.withTransaction(manager)
.retrieveDefault()
}
// Provided that the feature flag is enabled and
// no sales channels are available, set the default one
if (
featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key) &&
!validated?.sales_channels?.length
) {
const defaultSalesChannel = await salesChannelService
.withTransaction(manager)
.retrieveDefault()
validated.sales_channels = [defaultSalesChannel]
}
const newProduct = await productService
.withTransaction(manager)
.create({ ...validated, profile_id: shippingProfile.id })
if (variants) {
for (const [index, variant] of variants.entries()) {
variant["variant_rank"] = index
}
const optionIds =
validated?.options?.map(
(o) => newProduct.options.find((newO) => newO.title === o.title)?.id
) || []
const allVariantTransactions: DistributedTransaction[] = []
const transactionDependencies = {
manager,
inventoryService,
productVariantInventoryService,
productVariantService,
}
try {
const variantsInputData = variants.map((variant) => {
const options =
variant?.options?.map((option, index) => ({
...option,
option_id: optionIds[index],
})) || []
return {
...variant,
options,
} as CreateProductVariantInput
})
const varTransaction = await createVariantsTransaction(
transactionDependencies,
newProduct.id,
variantsInputData
)
allVariantTransactions.push(varTransaction)
} catch (e) {
await Promise.all(
allVariantTransactions.map(async (transaction) => {
await revertVariantTransaction(
transactionDependencies,
transaction
).catch(() => logger.warn("Transaction couldn't be reverted."))
})
)
throw e
}
}
const rawProduct = await productService
.withTransaction(manager)
.retrieve(newProduct.id, {
select: defaultAdminProductFields,
relations: defaultAdminProductRelations,
})
const [product] = await pricingService
.withTransaction(manager)
.setProductPrices([rawProduct])
return product
}) })
res.json({ product }) const [pricedProduct] = await pricingService.setProductPrices([rawProduct])
res.json({ product: pricedProduct })
} }
class ProductVariantOptionReq { class ProductVariantOptionReq {
@@ -22,7 +22,7 @@
"prepare": "cross-env NODE_ENV=production yarn run release", "prepare": "cross-env NODE_ENV=production yarn run release",
"build": "rollup --config --environment NODE_ENV:development", "build": "rollup --config --environment NODE_ENV:development",
"release": "rollup --config --environment NODE_ENV:production", "release": "rollup --config --environment NODE_ENV:production",
"test": "jest src" "test": "jest src --passWithNoTests"
}, },
"dependencies": { "dependencies": {
"camelcase": "^6.3.0", "camelcase": "^6.3.0",
@@ -787,6 +787,88 @@ describe("Transaction Orchestrator", () => {
expect(resumedTransaction.getState()).toBe(TransactionState.REVERTED) expect(resumedTransaction.getState()).toBe(TransactionState.REVERTED)
}) })
it("Should hold the status REVERTED if the steps failed and the compensation succeed and has some no compensations step set", async () => {
const mocks = {
one: jest.fn().mockImplementation((payload) => {
return
}),
compensateOne: jest.fn().mockImplementation((payload) => {
return
}),
two: jest.fn().mockImplementation((payload) => {
return
}),
compensateTwo: jest.fn().mockImplementation((payload) => {
return
}),
three: jest.fn().mockImplementation((payload) => {
throw new Error("Third step error")
}),
}
async function handler(
actionId: string,
functionHandlerType: TransactionHandlerType,
payload: TransactionPayload
) {
const command = {
firstMethod: {
[TransactionHandlerType.INVOKE]: () => {
mocks.one(payload)
},
[TransactionHandlerType.COMPENSATE]: () => {
mocks.compensateOne(payload)
},
},
secondMethod: {
[TransactionHandlerType.INVOKE]: () => {
mocks.two(payload)
},
[TransactionHandlerType.COMPENSATE]: () => {
mocks.compensateTwo(payload)
},
},
thirdMethod: {
[TransactionHandlerType.INVOKE]: () => {
mocks.three(payload)
},
},
}
return command[actionId][functionHandlerType](payload)
}
const flow: TransactionStepsDefinition = {
next: {
action: "firstMethod",
next: {
action: "secondMethod",
next: {
action: "thirdMethod",
noCompensation: true,
},
},
},
}
const strategy = new TransactionOrchestrator("transaction-name", flow)
const transaction = await strategy.beginTransaction(
"transaction_id_123",
handler
)
await strategy.resume(transaction)
expect(mocks.one).toBeCalledTimes(1)
expect(mocks.compensateOne).toBeCalledTimes(1)
expect(mocks.two).toBeCalledTimes(1)
expect(mocks.compensateTwo).toBeCalledTimes(1)
expect(mocks.three).toBeCalledTimes(1)
expect(transaction.getState()).toBe(TransactionState.REVERTED)
})
it("Should revert a transaction when .cancelTransaction() is called", async () => { it("Should revert a transaction when .cancelTransaction() is called", async () => {
const mocks = { const mocks = {
one: jest.fn().mockImplementation((payload) => { one: jest.fn().mockImplementation((payload) => {
@@ -147,8 +147,7 @@ describe("WorkflowManager", () => {
expect(handlers.get("bar").invoke).toHaveBeenCalledTimes(0) expect(handlers.get("bar").invoke).toHaveBeenCalledTimes(0)
expect(handlers.get("bar").compensate).toHaveBeenCalledTimes(0) expect(handlers.get("bar").compensate).toHaveBeenCalledTimes(0)
// Failed because the async is flagged as noCompensation expect(continuation.getState()).toBe(TransactionState.REVERTED)
expect(continuation.getState()).toBe(TransactionState.FAILED)
}) })
it("should update an existing global flow with a new step and a new handler", async () => { it("should update an existing global flow with a new step and a new handler", async () => {
@@ -146,8 +146,7 @@ describe("WorkflowManager", () => {
expect(handlers.get("bar").invoke).toHaveBeenCalledTimes(0) expect(handlers.get("bar").invoke).toHaveBeenCalledTimes(0)
expect(handlers.get("bar").compensate).toHaveBeenCalledTimes(0) expect(handlers.get("bar").compensate).toHaveBeenCalledTimes(0)
// Failed because the async is flagged as noCompensation expect(continuation.getState()).toBe(TransactionState.REVERTED)
expect(continuation.getState()).toBe(TransactionState.FAILED)
}) })
it("should update a flow with a new step and a new handler", async () => { it("should update a flow with a new step and a new handler", async () => {
@@ -74,9 +74,9 @@ export class DistributedTransaction {
public modelId: string public modelId: string
public transactionId: string public transactionId: string
private errors: TransactionStepError[] = [] private readonly errors: TransactionStepError[] = []
private context: TransactionContext = new TransactionContext() private readonly context: TransactionContext = new TransactionContext()
constructor( constructor(
private flow: TransactionFlow, private flow: TransactionFlow,
@@ -7,8 +7,8 @@ import { TransactionStep, TransactionStepHandler } from "./transaction-step"
import { import {
TransactionHandlerType, TransactionHandlerType,
TransactionState, TransactionState,
TransactionStepStatus,
TransactionStepsDefinition, TransactionStepsDefinition,
TransactionStepStatus,
} from "./types" } from "./types"
import { EventEmitter } from "events" import { EventEmitter } from "events"
@@ -233,9 +233,8 @@ export class TransactionOrchestrator extends EventEmitter {
const stepDef = flow.steps[step] const stepDef = flow.steps[step]
const curState = stepDef.getStates() const curState = stepDef.getStates()
if ( if (
(curState.state === TransactionState.DONE || curState.state === TransactionState.DONE ||
curState.status === TransactionStepStatus.PERMANENT_FAILURE) && curState.status === TransactionStepStatus.PERMANENT_FAILURE
!stepDef.definition.noCompensation
) { ) {
stepDef.beginCompensation() stepDef.beginCompensation()
stepDef.changeState(TransactionState.NOT_STARTED) stepDef.changeState(TransactionState.NOT_STARTED)
@@ -334,6 +333,11 @@ export class TransactionOrchestrator extends EventEmitter {
if (curState.state === TransactionState.NOT_STARTED) { if (curState.state === TransactionState.NOT_STARTED) {
if (step.isCompensating()) { if (step.isCompensating()) {
step.changeState(TransactionState.COMPENSATING) step.changeState(TransactionState.COMPENSATING)
if (step.definition.noCompensation) {
step.changeState(TransactionState.REVERTED)
continue
}
} else if (flow.state === TransactionState.INVOKING) { } else if (flow.state === TransactionState.INVOKING) {
step.changeState(TransactionState.INVOKING) step.changeState(TransactionState.INVOKING)
} }
@@ -1,5 +1,4 @@
import { ProductStatus } from "../../product" import { ProductStatus } from "../../product"
import { WorkflowInputConfig } from "../common"
export interface CreateProductTypeInputDTO { export interface CreateProductTypeInputDTO {
id?: string id?: string
@@ -92,5 +91,4 @@ export interface CreateProductInputDTO {
export interface CreateProductsWorkflowInputDTO { export interface CreateProductsWorkflowInputDTO {
products: CreateProductInputDTO[] products: CreateProductInputDTO[]
config?: WorkflowInputConfig
} }
+1 -1
View File
@@ -1,2 +1,2 @@
export * from "./create-products"
export * from "./cart" export * from "./cart"
export * from "./product"
@@ -1,19 +1,18 @@
import { InputAlias, Workflows } from "../definitions" import { InputAlias, Workflows } from "../../definitions"
import { import {
TransactionStepsDefinition, TransactionStepsDefinition,
WorkflowManager, WorkflowManager,
} from "@medusajs/orchestration" } from "@medusajs/orchestration"
import { exportWorkflow, pipe } from "../helper" import { aggregateData, exportWorkflow, pipe } from "../../helper"
import { ProductTypes, WorkflowTypes } from "@medusajs/types" import { ProductTypes, WorkflowTypes } from "@medusajs/types"
import { import {
InventoryHandlers, InventoryHandlers,
MiddlewaresHandlers, MiddlewaresHandlers,
ProductHandlers, ProductHandlers,
} from "../handlers" } from "../../handlers"
import { aggregateData } from "../helper/aggregate"
export enum Actions { export enum CreateProductsActions {
prepare = "prepare", prepare = "prepare",
createProducts = "createProducts", createProducts = "createProducts",
attachToSalesChannel = "attachToSalesChannel", attachToSalesChannel = "attachToSalesChannel",
@@ -21,34 +20,29 @@ export enum Actions {
createPrices = "createPrices", createPrices = "createPrices",
createInventoryItems = "createInventoryItems", createInventoryItems = "createInventoryItems",
attachInventoryItems = "attachInventoryItems", attachInventoryItems = "attachInventoryItems",
result = "result",
} }
export const workflowSteps: TransactionStepsDefinition = { export const workflowSteps: TransactionStepsDefinition = {
next: { next: {
action: Actions.prepare, action: CreateProductsActions.prepare,
noCompensation: true, noCompensation: true,
next: { next: {
action: Actions.createProducts, action: CreateProductsActions.createProducts,
next: [ next: [
{ {
action: Actions.attachShippingProfile, action: CreateProductsActions.attachShippingProfile,
saveResponse: false, saveResponse: false,
}, },
{ {
action: Actions.attachToSalesChannel, action: CreateProductsActions.attachToSalesChannel,
saveResponse: false, saveResponse: false,
}, },
{ {
action: Actions.createPrices, action: CreateProductsActions.createPrices,
next: { next: {
action: Actions.createInventoryItems, action: CreateProductsActions.createInventoryItems,
next: { next: {
action: Actions.attachInventoryItems, action: CreateProductsActions.attachInventoryItems,
next: {
action: Actions.result,
noCompensation: true,
},
}, },
}, },
}, },
@@ -59,7 +53,7 @@ export const workflowSteps: TransactionStepsDefinition = {
const handlers = new Map([ const handlers = new Map([
[ [
Actions.prepare, CreateProductsActions.prepare,
{ {
invoke: pipe( invoke: pipe(
{ {
@@ -69,17 +63,17 @@ const handlers = new Map([
}, },
}, },
aggregateData(), aggregateData(),
MiddlewaresHandlers.createProductsPrepareData ProductHandlers.createProductsPrepareData
), ),
}, },
], ],
[ [
Actions.createProducts, CreateProductsActions.createProducts,
{ {
invoke: pipe( invoke: pipe(
{ {
invoke: { invoke: {
from: Actions.prepare, from: CreateProductsActions.prepare,
}, },
}, },
aggregateData(), aggregateData(),
@@ -88,7 +82,7 @@ const handlers = new Map([
compensate: pipe( compensate: pipe(
{ {
invoke: { invoke: {
from: Actions.createProducts, from: CreateProductsActions.createProducts,
alias: ProductHandlers.removeProducts.aliases.products, alias: ProductHandlers.removeProducts.aliases.products,
}, },
}, },
@@ -98,16 +92,16 @@ const handlers = new Map([
}, },
], ],
[ [
Actions.attachShippingProfile, CreateProductsActions.attachShippingProfile,
{ {
invoke: pipe( invoke: pipe(
{ {
invoke: [ invoke: [
{ {
from: Actions.prepare, from: CreateProductsActions.prepare,
}, },
{ {
from: Actions.createProducts, from: CreateProductsActions.createProducts,
alias: alias:
ProductHandlers.attachShippingProfileToProducts.aliases ProductHandlers.attachShippingProfileToProducts.aliases
.products, .products,
@@ -121,10 +115,10 @@ const handlers = new Map([
{ {
invoke: [ invoke: [
{ {
from: Actions.prepare, from: CreateProductsActions.prepare,
}, },
{ {
from: Actions.createProducts, from: CreateProductsActions.createProducts,
alias: alias:
ProductHandlers.detachShippingProfileFromProducts.aliases ProductHandlers.detachShippingProfileFromProducts.aliases
.products, .products,
@@ -137,16 +131,16 @@ const handlers = new Map([
}, },
], ],
[ [
Actions.attachToSalesChannel, CreateProductsActions.attachToSalesChannel,
{ {
invoke: pipe( invoke: pipe(
{ {
invoke: [ invoke: [
{ {
from: Actions.prepare, from: CreateProductsActions.prepare,
}, },
{ {
from: Actions.createProducts, from: CreateProductsActions.createProducts,
alias: alias:
ProductHandlers.attachSalesChannelToProducts.aliases.products, ProductHandlers.attachSalesChannelToProducts.aliases.products,
}, },
@@ -159,10 +153,10 @@ const handlers = new Map([
{ {
invoke: [ invoke: [
{ {
from: Actions.prepare, from: CreateProductsActions.prepare,
}, },
{ {
from: Actions.createProducts, from: CreateProductsActions.createProducts,
alias: alias:
ProductHandlers.detachSalesChannelFromProducts.aliases.products, ProductHandlers.detachSalesChannelFromProducts.aliases.products,
}, },
@@ -174,12 +168,12 @@ const handlers = new Map([
}, },
], ],
[ [
Actions.createInventoryItems, CreateProductsActions.createInventoryItems,
{ {
invoke: pipe( invoke: pipe(
{ {
invoke: { invoke: {
from: Actions.createProducts, from: CreateProductsActions.createProducts,
alias: InventoryHandlers.createInventoryItems.aliases.products, alias: InventoryHandlers.createInventoryItems.aliases.products,
}, },
}, },
@@ -189,7 +183,7 @@ const handlers = new Map([
compensate: pipe( compensate: pipe(
{ {
invoke: { invoke: {
from: Actions.createInventoryItems, from: CreateProductsActions.createInventoryItems,
alias: alias:
InventoryHandlers.removeInventoryItems.aliases.inventoryItems, InventoryHandlers.removeInventoryItems.aliases.inventoryItems,
}, },
@@ -200,12 +194,12 @@ const handlers = new Map([
}, },
], ],
[ [
Actions.attachInventoryItems, CreateProductsActions.attachInventoryItems,
{ {
invoke: pipe( invoke: pipe(
{ {
invoke: { invoke: {
from: Actions.createInventoryItems, from: CreateProductsActions.createInventoryItems,
alias: alias:
InventoryHandlers.attachInventoryItems.aliases.inventoryItems, InventoryHandlers.attachInventoryItems.aliases.inventoryItems,
}, },
@@ -216,7 +210,7 @@ const handlers = new Map([
compensate: pipe( compensate: pipe(
{ {
invoke: { invoke: {
from: Actions.createInventoryItems, from: CreateProductsActions.createInventoryItems,
alias: alias:
InventoryHandlers.detachInventoryItems.aliases.inventoryItems, InventoryHandlers.detachInventoryItems.aliases.inventoryItems,
}, },
@@ -227,16 +221,16 @@ const handlers = new Map([
}, },
], ],
[ [
Actions.createPrices, CreateProductsActions.createPrices,
{ {
invoke: pipe( invoke: pipe(
{ {
invoke: [ invoke: [
{ {
from: Actions.prepare, from: CreateProductsActions.prepare,
}, },
{ {
from: Actions.createProducts, from: CreateProductsActions.createProducts,
alias: alias:
ProductHandlers.updateProductsVariantsPrices.aliases.products, ProductHandlers.updateProductsVariantsPrices.aliases.products,
}, },
@@ -249,10 +243,10 @@ const handlers = new Map([
{ {
invoke: [ invoke: [
{ {
from: Actions.prepare, from: CreateProductsActions.prepare,
}, },
{ {
from: Actions.createProducts, from: CreateProductsActions.createProducts,
alias: alias:
ProductHandlers.updateProductsVariantsPrices.aliases.products, ProductHandlers.updateProductsVariantsPrices.aliases.products,
}, },
@@ -264,32 +258,6 @@ const handlers = new Map([
), ),
}, },
], ],
[
Actions.result,
{
invoke: pipe(
{
invoke: [
{
from: Actions.prepare,
},
{
from: Actions.createProducts,
alias: "products",
},
],
},
async ({ data }) => {
return {
alias: ProductHandlers.listProducts.aliases.ids,
value: data.products.map((product) => product.id),
}
},
aggregateData(),
ProductHandlers.listProducts
),
},
],
]) ])
WorkflowManager.register(Workflows.CreateProducts, workflowSteps, handlers) WorkflowManager.register(Workflows.CreateProducts, workflowSteps, handlers)
@@ -297,4 +265,4 @@ WorkflowManager.register(Workflows.CreateProducts, workflowSteps, handlers)
export const createProducts = exportWorkflow< export const createProducts = exportWorkflow<
WorkflowTypes.ProductWorkflow.CreateProductsWorkflowInputDTO, WorkflowTypes.ProductWorkflow.CreateProductsWorkflowInputDTO,
ProductTypes.ProductDTO[] ProductTypes.ProductDTO[]
>(Workflows.CreateProducts, Actions.result) >(Workflows.CreateProducts, CreateProductsActions.createProducts)
@@ -0,0 +1 @@
export * from "./create-products"
@@ -1,2 +1 @@
export * from "./create-products-prepare-create-prices-compensation" export * from "./create-products-prepare-create-prices-compensation"
export * from "./create-products-prepare-data"
@@ -28,7 +28,6 @@ export type CreateProductsPreparedData = {
ProductHandle, ProductHandle,
VariantIndexAndPrices[] VariantIndexAndPrices[]
> >
config?: WorkflowTypes.CommonWorkflow.WorkflowInputConfig
} }
export async function createProductsPrepareData({ export async function createProductsPrepareData({
@@ -145,7 +144,6 @@ export async function createProductsPrepareData({
productsHandleShippingProfileIdMap, productsHandleShippingProfileIdMap,
productsHandleSalesChannelsMap, productsHandleSalesChannelsMap,
productsHandleVariantsIndexPricesMap, productsHandleVariantsIndexPricesMap,
config: data.config,
} }
} }
@@ -1,3 +1,4 @@
export * from "./create-products-prepare-data"
export * from "./create-products" export * from "./create-products"
export * from "./detach-sales-channel-from-products" export * from "./detach-sales-channel-from-products"
export * from "./attach-sales-channel-to-products" export * from "./attach-sales-channel-to-products"