feat: add product admin v2 endpoints (#6579)
This implementation obviously lacks a lot of things, and there are a lot of TODOs. However, there are already a lot of questions I'd rather get answered soon, so I figured it's much easier to do the implementation in steps. I wrote down all breaking changes, suggested changes, and new additions with comments (TODO and Note). In a follow-up PR I will: Add the remaining/missing models Make the workflows handle all interactions between the different models/modules Add integration tests
This commit is contained in:
@@ -10,3 +10,4 @@ export * from "./user"
|
||||
export * from "./tax"
|
||||
export * from "./api-key"
|
||||
export * from "./store"
|
||||
export * from "./product"
|
||||
|
||||
2
packages/core-flows/src/product/index.ts
Normal file
2
packages/core-flows/src/product/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./steps"
|
||||
export * from "./workflows"
|
||||
@@ -0,0 +1,30 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService, ProductTypes } from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const createProductOptionsStepId = "create-product-options"
|
||||
export const createProductOptionsStep = createStep(
|
||||
createProductOptionsStepId,
|
||||
async (data: ProductTypes.CreateProductOptionDTO[], { container }) => {
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
const created = await service.createOptions(data)
|
||||
return new StepResponse(
|
||||
created,
|
||||
created.map((productOption) => productOption.id)
|
||||
)
|
||||
},
|
||||
async (createdIds, { container }) => {
|
||||
if (!createdIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
await service.deleteOptions(createdIds)
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService, ProductTypes } from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const createProductVariantsStepId = "create-product-variants"
|
||||
export const createProductVariantsStep = createStep(
|
||||
createProductVariantsStepId,
|
||||
async (data: ProductTypes.CreateProductVariantDTO[], { container }) => {
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
const created = await service.createVariants(data)
|
||||
return new StepResponse(
|
||||
created,
|
||||
created.map((productVariant) => productVariant.id)
|
||||
)
|
||||
},
|
||||
async (createdIds, { container }) => {
|
||||
if (!createdIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
await service.deleteVariants(createdIds)
|
||||
}
|
||||
)
|
||||
30
packages/core-flows/src/product/steps/create-products.ts
Normal file
30
packages/core-flows/src/product/steps/create-products.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService, ProductTypes } from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const createProductsStepId = "create-products"
|
||||
export const createProductsStep = createStep(
|
||||
createProductsStepId,
|
||||
async (data: ProductTypes.CreateProductDTO[], { container }) => {
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
const created = await service.create(data)
|
||||
return new StepResponse(
|
||||
created,
|
||||
created.map((product) => product.id)
|
||||
)
|
||||
},
|
||||
async (createdIds, { container }) => {
|
||||
if (!createdIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
await service.delete(createdIds)
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService } from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const deleteProductOptionsStepId = "delete-product-options"
|
||||
export const deleteProductOptionsStep = createStep(
|
||||
deleteProductOptionsStepId,
|
||||
async (ids: string[], { container }) => {
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
await service.softDeleteOptions(ids)
|
||||
return new StepResponse(void 0, ids)
|
||||
},
|
||||
async (prevIds, { container }) => {
|
||||
if (!prevIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
await service.restoreOptions(prevIds)
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService } from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const deleteProductVariantsStepId = "delete-product-variants"
|
||||
export const deleteProductVariantsStep = createStep(
|
||||
deleteProductVariantsStepId,
|
||||
async (ids: string[], { container }) => {
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
await service.softDeleteVariants(ids)
|
||||
return new StepResponse(void 0, ids)
|
||||
},
|
||||
async (prevIds, { container }) => {
|
||||
if (!prevIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
await service.restoreVariants(prevIds)
|
||||
}
|
||||
)
|
||||
27
packages/core-flows/src/product/steps/delete-products.ts
Normal file
27
packages/core-flows/src/product/steps/delete-products.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService } from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const deleteProductsStepId = "delete-products"
|
||||
export const deleteProductsStep = createStep(
|
||||
deleteProductsStepId,
|
||||
async (ids: string[], { container }) => {
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
await service.softDelete(ids)
|
||||
return new StepResponse(void 0, ids)
|
||||
},
|
||||
async (prevIds, { container }) => {
|
||||
if (!prevIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
await service.restore(prevIds)
|
||||
}
|
||||
)
|
||||
9
packages/core-flows/src/product/steps/index.ts
Normal file
9
packages/core-flows/src/product/steps/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export * from "./create-products"
|
||||
export * from "./update-products"
|
||||
export * from "./delete-products"
|
||||
export * from "./create-product-options"
|
||||
export * from "./update-product-options"
|
||||
export * from "./delete-product-options"
|
||||
export * from "./create-product-variants"
|
||||
export * from "./update-product-variants"
|
||||
export * from "./delete-product-variants"
|
||||
@@ -0,0 +1,49 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService, ProductTypes } from "@medusajs/types"
|
||||
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
type UpdateProductOptionsStepInput = {
|
||||
selector: ProductTypes.FilterableProductOptionProps
|
||||
update: ProductTypes.UpdateProductOptionDTO
|
||||
}
|
||||
|
||||
export const updateProductOptionsStepId = "update-product-options"
|
||||
export const updateProductOptionsStep = createStep(
|
||||
updateProductOptionsStepId,
|
||||
async (data: UpdateProductOptionsStepInput, { container }) => {
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
|
||||
data.update,
|
||||
])
|
||||
|
||||
const prevData = await service.listOptions(data.selector, {
|
||||
select: selects,
|
||||
relations,
|
||||
})
|
||||
|
||||
// TODO: We need to update the module's signature
|
||||
// const productOptions = await service.updateOptions(data.selector, data.update)
|
||||
const productOptions = []
|
||||
return new StepResponse(productOptions, prevData)
|
||||
},
|
||||
async (prevData, { container }) => {
|
||||
if (!prevData?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
// TODO: We need to update the module's signature
|
||||
// await service.upsertOptions(
|
||||
// prevData.map((r) => ({
|
||||
// ...r,
|
||||
// }))
|
||||
// )
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService, ProductTypes } from "@medusajs/types"
|
||||
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
type UpdateProductVariantsStepInput = {
|
||||
selector: ProductTypes.FilterableProductVariantProps
|
||||
update: ProductTypes.UpdateProductVariantDTO
|
||||
}
|
||||
|
||||
export const updateProductVariantsStepId = "update-product-variants"
|
||||
export const updateProductVariantsStep = createStep(
|
||||
updateProductVariantsStepId,
|
||||
async (data: UpdateProductVariantsStepInput, { container }) => {
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
|
||||
data.update,
|
||||
])
|
||||
|
||||
const prevData = await service.listVariants(data.selector, {
|
||||
select: selects,
|
||||
relations,
|
||||
})
|
||||
|
||||
// TODO: We need to update the module's signature
|
||||
// const productVariants = await service.updateVariants(data.selector, data.update)
|
||||
const productVariants = []
|
||||
return new StepResponse(productVariants, prevData)
|
||||
},
|
||||
async (prevData, { container }) => {
|
||||
if (!prevData?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
// TODO: We need to update the module's signature
|
||||
// await service.upsertVariants(
|
||||
// prevData.map((r) => ({
|
||||
// ...r,
|
||||
// }))
|
||||
// )
|
||||
}
|
||||
)
|
||||
49
packages/core-flows/src/product/steps/update-products.ts
Normal file
49
packages/core-flows/src/product/steps/update-products.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService, ProductTypes } from "@medusajs/types"
|
||||
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
type UpdateProductsStepInput = {
|
||||
selector: ProductTypes.FilterableProductProps
|
||||
update: ProductTypes.UpdateProductDTO
|
||||
}
|
||||
|
||||
export const updateProductsStepId = "update-products"
|
||||
export const updateProductsStep = createStep(
|
||||
updateProductsStepId,
|
||||
async (data: UpdateProductsStepInput, { container }) => {
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
|
||||
data.update,
|
||||
])
|
||||
|
||||
const prevData = await service.list(data.selector, {
|
||||
select: selects,
|
||||
relations,
|
||||
})
|
||||
|
||||
// TODO: We need to update the module's signature
|
||||
// const products = await service.update(data.selector, data.update)
|
||||
const products = []
|
||||
return new StepResponse(products, prevData)
|
||||
},
|
||||
async (prevData, { container }) => {
|
||||
if (!prevData?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IProductModuleService>(
|
||||
ModuleRegistrationName.PRODUCT
|
||||
)
|
||||
|
||||
// TODO: We need to update the module's signature
|
||||
// await service.upsert(
|
||||
// prevData.map((r) => ({
|
||||
// ...r,
|
||||
// }))
|
||||
// )
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { createProductOptionsStep } from "../steps"
|
||||
|
||||
type WorkflowInput = { product_options: ProductTypes.CreateProductOptionDTO[] }
|
||||
|
||||
export const createProductOptionsWorkflowId = "create-product-options"
|
||||
export const createProductOptionsWorkflow = createWorkflow(
|
||||
createProductOptionsWorkflowId,
|
||||
(
|
||||
input: WorkflowData<WorkflowInput>
|
||||
): WorkflowData<ProductTypes.ProductOptionDTO[]> => {
|
||||
return createProductOptionsStep(input.product_options)
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { createProductVariantsStep } from "../steps"
|
||||
|
||||
type WorkflowInput = {
|
||||
product_variants: ProductTypes.CreateProductVariantDTO[]
|
||||
}
|
||||
|
||||
export const createProductVariantsWorkflowId = "create-product-variants"
|
||||
export const createProductVariantsWorkflow = createWorkflow(
|
||||
createProductVariantsWorkflowId,
|
||||
(
|
||||
input: WorkflowData<WorkflowInput>
|
||||
): WorkflowData<ProductTypes.ProductVariantDTO[]> => {
|
||||
return createProductVariantsStep(input.product_variants)
|
||||
}
|
||||
)
|
||||
15
packages/core-flows/src/product/workflows/create-products.ts
Normal file
15
packages/core-flows/src/product/workflows/create-products.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { createProductsStep } from "../steps"
|
||||
|
||||
type WorkflowInput = { products: ProductTypes.CreateProductDTO[] }
|
||||
|
||||
export const createProductsWorkflowId = "create-products"
|
||||
export const createProductsWorkflow = createWorkflow(
|
||||
createProductsWorkflowId,
|
||||
(
|
||||
input: WorkflowData<WorkflowInput>
|
||||
): WorkflowData<ProductTypes.ProductDTO[]> => {
|
||||
return createProductsStep(input.products)
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { deleteProductOptionsStep } from "../steps"
|
||||
|
||||
type WorkflowInput = { ids: string[] }
|
||||
|
||||
export const deleteProductOptionsWorkflowId = "delete-product-options"
|
||||
export const deleteProductOptionsWorkflow = createWorkflow(
|
||||
deleteProductOptionsWorkflowId,
|
||||
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||
return deleteProductOptionsStep(input.ids)
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { deleteProductVariantsStep } from "../steps"
|
||||
|
||||
type WorkflowInput = { ids: string[] }
|
||||
|
||||
export const deleteProductVariantsWorkflowId = "delete-product-variants"
|
||||
export const deleteProductVariantsWorkflow = createWorkflow(
|
||||
deleteProductVariantsWorkflowId,
|
||||
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||
return deleteProductVariantsStep(input.ids)
|
||||
}
|
||||
)
|
||||
12
packages/core-flows/src/product/workflows/delete-products.ts
Normal file
12
packages/core-flows/src/product/workflows/delete-products.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { deleteProductsStep } from "../steps"
|
||||
|
||||
type WorkflowInput = { ids: string[] }
|
||||
|
||||
export const deleteProductsWorkflowId = "delete-products"
|
||||
export const deleteProductsWorkflow = createWorkflow(
|
||||
deleteProductsWorkflowId,
|
||||
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||
return deleteProductsStep(input.ids)
|
||||
}
|
||||
)
|
||||
9
packages/core-flows/src/product/workflows/index.ts
Normal file
9
packages/core-flows/src/product/workflows/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export * from "./create-products"
|
||||
export * from "./delete-products"
|
||||
export * from "./update-products"
|
||||
export * from "./create-product-options"
|
||||
export * from "./delete-product-options"
|
||||
export * from "./update-product-options"
|
||||
export * from "./create-product-variants"
|
||||
export * from "./delete-product-variants"
|
||||
export * from "./update-product-variants"
|
||||
@@ -0,0 +1,20 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { updateProductOptionsStep } from "../steps"
|
||||
|
||||
type UpdateProductOptionsStepInput = {
|
||||
selector: ProductTypes.FilterableProductOptionProps
|
||||
update: ProductTypes.UpdateProductOptionDTO
|
||||
}
|
||||
|
||||
type WorkflowInput = UpdateProductOptionsStepInput
|
||||
|
||||
export const updateProductOptionsWorkflowId = "update-product-options"
|
||||
export const updateProductOptionsWorkflow = createWorkflow(
|
||||
updateProductOptionsWorkflowId,
|
||||
(
|
||||
input: WorkflowData<WorkflowInput>
|
||||
): WorkflowData<ProductTypes.ProductOptionDTO[]> => {
|
||||
return updateProductOptionsStep(input)
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { updateProductVariantsStep } from "../steps"
|
||||
|
||||
type UpdateProductVariantsStepInput = {
|
||||
selector: ProductTypes.FilterableProductVariantProps
|
||||
update: ProductTypes.UpdateProductVariantDTO
|
||||
}
|
||||
|
||||
type WorkflowInput = UpdateProductVariantsStepInput
|
||||
|
||||
export const updateProductVariantsWorkflowId = "update-product-variants"
|
||||
export const updateProductVariantsWorkflow = createWorkflow(
|
||||
updateProductVariantsWorkflowId,
|
||||
(
|
||||
input: WorkflowData<WorkflowInput>
|
||||
): WorkflowData<ProductTypes.ProductVariantDTO[]> => {
|
||||
return updateProductVariantsStep(input)
|
||||
}
|
||||
)
|
||||
20
packages/core-flows/src/product/workflows/update-products.ts
Normal file
20
packages/core-flows/src/product/workflows/update-products.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { updateProductsStep } from "../steps"
|
||||
|
||||
type UpdateProductsStepInput = {
|
||||
selector: ProductTypes.FilterableProductProps
|
||||
update: ProductTypes.UpdateProductDTO
|
||||
}
|
||||
|
||||
type WorkflowInput = UpdateProductsStepInput
|
||||
|
||||
export const updateProductsWorkflowId = "update-products"
|
||||
export const updateProductsWorkflow = createWorkflow(
|
||||
updateProductsWorkflowId,
|
||||
(
|
||||
input: WorkflowData<WorkflowInput>
|
||||
): WorkflowData<ProductTypes.ProductDTO[]> => {
|
||||
return updateProductsStep(input)
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user