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:
Stevche Radevski
2024-03-05 11:24:33 +01:00
committed by GitHub
parent 7d69e6068e
commit f9ef37a2f2
35 changed files with 1924 additions and 2 deletions

View File

@@ -10,3 +10,4 @@ export * from "./user"
export * from "./tax"
export * from "./api-key"
export * from "./store"
export * from "./product"

View File

@@ -0,0 +1,2 @@
export * from "./steps"
export * from "./workflows"

View 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 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)
}
)

View 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 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)
}
)

View 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)
}
)

View 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 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)
}
)

View 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 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)
}
)

View 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)
}
)

View 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"

View 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 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,
// }))
// )
}
)

View 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 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,
// }))
// )
}
)

View 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,
// }))
// )
}
)

View File

@@ -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)
}
)

View File

@@ -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)
}
)

View 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)
}
)

View File

@@ -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)
}
)

View File

@@ -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)
}
)

View 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)
}
)

View 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"

View File

@@ -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)
}
)

View File

@@ -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)
}
)

View 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)
}
)