feat: Convert several batch methods to the standardized format (#7116)

This commit is contained in:
Stevche Radevski authored and GitHub committed 2024-04-22 16:35:10 +02:00
1 parent 0eb68541b8
commit 0df523594f
63 files changed
+614 -919

No files matched your search

@@ -188,14 +188,19 @@ medusaIntegrationTestRunner({
const { api_key } = apiKeyRes.data const { api_key } = apiKeyRes.data
const keyWithChannelsRes = await api.post( const keyWithChannelsRes = await api.post(
`/admin/api-keys/${api_key.id}/sales-channels/batch`, `/admin/api-keys/${api_key.id}/sales-channels`,
{ {
create: [sales_channel.id], add: [sales_channel.id],
}, },
adminHeaders adminHeaders
) )
const { api_key: keyWithChannels } = keyWithChannelsRes.data const keyWithChannels = (
await api.get(
`/admin/api-keys/${api_key.id}?fields=*sales_channels`,
adminHeaders
)
).data.api_key
expect(keyWithChannelsRes.status).toEqual(200) expect(keyWithChannelsRes.status).toEqual(200)
expect(keyWithChannels.title).toEqual("Test publishable KEY") expect(keyWithChannels.title).toEqual("Test publishable KEY")
@@ -229,9 +234,9 @@ medusaIntegrationTestRunner({
const errorRes = await api const errorRes = await api
.post( .post(
`/admin/api-keys/${apiKeyRes.data.api_key.id}/sales-channels/batch`, `/admin/api-keys/${apiKeyRes.data.api_key.id}/sales-channels`,
{ {
create: [sales_channel.id], add: [sales_channel.id],
}, },
adminHeaders adminHeaders
) )
@@ -255,9 +260,9 @@ medusaIntegrationTestRunner({
const errorRes = await api const errorRes = await api
.post( .post(
`/admin/api-keys/${apiKeyRes.data.api_key.id}/sales-channels/batch`, `/admin/api-keys/${apiKeyRes.data.api_key.id}/sales-channels`,
{ {
create: ["phony"], add: ["phony"],
}, },
adminHeaders adminHeaders
) )
@@ -292,14 +297,19 @@ medusaIntegrationTestRunner({
const { api_key } = apiKeyRes.data const { api_key } = apiKeyRes.data
const keyWithChannelsRes = await api.post( const keyWithChannelsRes = await api.post(
`/admin/api-keys/${api_key.id}/sales-channels/batch`, `/admin/api-keys/${api_key.id}/sales-channels`,
{ {
create: [sales_channel.id], add: [sales_channel.id],
}, },
adminHeaders adminHeaders
) )
const { api_key: keyWithChannels } = keyWithChannelsRes.data const keyWithChannels = (
await api.get(
`/admin/api-keys/${api_key.id}?fields=*sales_channels`,
adminHeaders
)
).data.api_key
expect(keyWithChannelsRes.status).toEqual(200) expect(keyWithChannelsRes.status).toEqual(200)
expect(keyWithChannels.title).toEqual("Test publishable KEY") expect(keyWithChannels.title).toEqual("Test publishable KEY")
@@ -311,14 +321,19 @@ medusaIntegrationTestRunner({
]) ])
const keyWithoutChannelsRes = await api.post( const keyWithoutChannelsRes = await api.post(
`/admin/api-keys/${api_key.id}/sales-channels/batch`, `/admin/api-keys/${api_key.id}/sales-channels`,
{ {
delete: [sales_channel.id], remove: [sales_channel.id],
}, },
adminHeaders adminHeaders
) )
const { api_key: keyWithoutChannels } = keyWithoutChannelsRes.data const keyWithoutChannels = (
await api.get(
`/admin/api-keys/${api_key.id}?fields=*sales_channels`,
adminHeaders
)
).data.api_key
expect(keyWithoutChannelsRes.status).toEqual(200) expect(keyWithoutChannelsRes.status).toEqual(200)
expect(keyWithoutChannels.title).toEqual("Test publishable KEY") expect(keyWithoutChannels.title).toEqual("Test publishable KEY")
@@ -348,14 +363,19 @@ medusaIntegrationTestRunner({
const { api_key } = apiKeyRes.data const { api_key } = apiKeyRes.data
const keyWithChannelsRes = await api.post( const keyWithChannelsRes = await api.post(
`/admin/api-keys/${api_key.id}/sales-channels/batch`, `/admin/api-keys/${api_key.id}/sales-channels`,
{ {
create: [sales_channel.id], add: [sales_channel.id],
}, },
adminHeaders adminHeaders
) )
const { api_key: keyWithChannels } = keyWithChannelsRes.data const keyWithChannels = (
await api.get(
`/admin/api-keys/${api_key.id}?fields=*sales_channels`,
adminHeaders
)
).data.api_key
expect(keyWithChannelsRes.status).toEqual(200) expect(keyWithChannelsRes.status).toEqual(200)
expect(keyWithChannels.title).toEqual("Test publishable KEY") expect(keyWithChannels.title).toEqual("Test publishable KEY")
@@ -2998,8 +2998,7 @@ medusaIntegrationTestRunner({
) )
expect(response.status).toEqual(200) expect(response.status).toEqual(200)
expect(response.data.added).toHaveLength(1) expect(response.data.collection).toBeTruthy()
expect(response.data.removed).toHaveLength(1)
const collection = ( const collection = (
await api.get( await api.get(
@@ -318,9 +318,9 @@ medusaIntegrationTestRunner({
scId = scResponse.data.sales_channel.id scId = scResponse.data.sales_channel.id
await api.post( await api.post(
`/admin/stock-locations/${location}/sales-channels/batch/add`, `/admin/stock-locations/${location}/sales-channels`,
{ {
sales_channel_ids: [scId], add: [scId],
}, },
adminHeaders adminHeaders
) )
@@ -827,7 +827,7 @@ medusaIntegrationTestRunner({
describe("POST /admin/sales-channels/:id/products/batch", () => { describe("POST /admin/sales-channels/:id/products/batch", () => {
// BREAKING CHANGE: Endpoint has changed // BREAKING CHANGE: Endpoint has changed
// from: /admin/sales-channels/:id/products/batch // from: /admin/sales-channels/:id/products/batch
// to: /admin/sales-channels/:id/products/batch/add // to: /admin/sales-channels/:id/products
let { salesChannel, product } = {} let { salesChannel, product } = {}
@@ -860,12 +860,14 @@ medusaIntegrationTestRunner({
}) })
it("should add products to a sales channel", async () => { it("should add products to a sales channel", async () => {
const payload = { const payload = breaking(
product_ids: breaking( () => ({
() => [{ id: product.id }], product_ids: [{ id: product.id }],
() => [product.id] }),
), () => ({
} add: [product.id],
})
)
const response = await breaking( const response = await breaking(
async () => { async () => {
@@ -877,7 +879,7 @@ medusaIntegrationTestRunner({
}, },
async () => { async () => {
return await api.post( return await api.post(
`/admin/sales-channels/${salesChannel.id}/products/batch/add`, `/admin/sales-channels/${salesChannel.id}/products`,
payload, payload,
adminReqConfig adminReqConfig
) )
@@ -308,8 +308,8 @@ medusaIntegrationTestRunner({
it("should add sales channels to a location", async () => { it("should add sales channels to a location", async () => {
const salesChannelResponse = await api.post( const salesChannelResponse = await api.post(
`/admin/stock-locations/${location.id}/sales-channels/batch/add?fields=*sales_channels`, `/admin/stock-locations/${location.id}/sales-channels?fields=*sales_channels`,
{ sales_channel_ids: [salesChannel.id] }, { add: [salesChannel.id] },
adminHeaders adminHeaders
) )
@@ -356,16 +356,16 @@ medusaIntegrationTestRunner({
location = locationResponse.data.stock_location location = locationResponse.data.stock_location
await api.post( await api.post(
`/admin/stock-locations/${location.id}/sales-channels/batch/add?fields=*sales_channels`, `/admin/stock-locations/${location.id}/sales-channels?fields=*sales_channels`,
{ sales_channel_ids: [salesChannel1.id, salesChannel2.id] }, { add: [salesChannel1.id, salesChannel2.id] },
adminHeaders adminHeaders
) )
}) })
it("should remove sales channels from a location", async () => { it("should remove sales channels from a location", async () => {
const salesChannelResponse = await api.post( const salesChannelResponse = await api.post(
`/admin/stock-locations/${location.id}/sales-channels/batch/remove?fields=*sales_channels`, `/admin/stock-locations/${location.id}/sales-channels?fields=*sales_channels`,
{ sales_channel_ids: [salesChannel1.id] }, { remove: [salesChannel1.id] },
adminHeaders adminHeaders
) )
@@ -13,7 +13,7 @@ const adminHeaders = {
medusaIntegrationTestRunner({ medusaIntegrationTestRunner({
env, env,
testSuite: ({ dbConnection, getContainer, api }) => { testSuite: ({ dbConnection, getContainer, api }) => {
describe("POST /admin/customer-groups/:id/customers/batch", () => { describe("POST /admin/customer-groups/:id/customers", () => {
let appContainer let appContainer
let customerModuleService: ICustomerModuleService let customerModuleService: ICustomerModuleService
@@ -48,9 +48,9 @@ medusaIntegrationTestRunner({
]) ])
const response = await api.post( const response = await api.post(
`/admin/customer-groups/${group.id}/customers/batch`, `/admin/customer-groups/${group.id}/customers`,
{ {
create: customers.map((c) => c.id), add: customers.map((c) => c.id),
}, },
adminHeaders adminHeaders
) )
@@ -13,7 +13,7 @@ const adminHeaders = {
medusaIntegrationTestRunner({ medusaIntegrationTestRunner({
env, env,
testSuite: ({ dbConnection, getContainer, api }) => { testSuite: ({ dbConnection, getContainer, api }) => {
describe("POST /admin/customer-groups/:id/customers/batch", () => { describe("POST /admin/customer-groups/:id/customers", () => {
let appContainer let appContainer
let customerModuleService: ICustomerModuleService let customerModuleService: ICustomerModuleService
@@ -55,9 +55,9 @@ medusaIntegrationTestRunner({
) )
const response = await api.post( const response = await api.post(
`/admin/customer-groups/${group.id}/customers/batch`, `/admin/customer-groups/${group.id}/customers`,
{ {
delete: customers.map((c) => c.id), remove: customers.map((c) => c.id),
}, },
adminHeaders adminHeaders
) )
@@ -1,51 +0,0 @@
import { Modules } from "@medusajs/modules-sdk"
import { ContainerRegistrationKeys } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
interface StepInput {
links: {
api_key_id: string
sales_channel_ids: string[]
}[]
}
export const associateApiKeysWithSalesChannelsStepId =
"associate-sales-channels-with-api-keys"
export const associateApiKeysWithSalesChannelsStep = createStep(
associateApiKeysWithSalesChannelsStepId,
async (input: StepInput, { container }) => {
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
if (!input.links) {
return
}
const links = input.links
.map((link) => {
return link.sales_channel_ids.map((id) => {
return {
[Modules.API_KEY]: {
publishable_key_id: link.api_key_id,
},
[Modules.SALES_CHANNEL]: {
sales_channel_id: id,
},
}
})
})
.flat()
const createdLinks = await remoteLink.create(links)
return new StepResponse(createdLinks, links)
},
async (links, { container }) => {
if (!links) {
return
}
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
await remoteLink.dismiss(links)
}
)
@@ -1,47 +0,0 @@
import { Modules } from "@medusajs/modules-sdk"
import { ContainerRegistrationKeys } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
interface StepInput {
links: {
api_key_id: string
sales_channel_ids: string[]
}[]
}
export const detachApiKeysWithSalesChannelsStepId =
"detach-sales-channels-with-api-keys"
export const detachApiKeysWithSalesChannelsStep = createStep(
detachApiKeysWithSalesChannelsStepId,
async (input: StepInput, { container }) => {
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
const links = input.links
.map((link) => {
return link.sales_channel_ids.map((id) => {
return {
[Modules.API_KEY]: {
publishable_key_id: link.api_key_id,
},
[Modules.SALES_CHANNEL]: {
sales_channel_id: id,
},
}
})
})
.flat()
await remoteLink.dismiss(links)
return new StepResponse(void 0, links)
},
async (links, { container }) => {
if (!links?.length) {
return
}
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
await remoteLink.create(links)
}
)
@@ -1,7 +1,6 @@
export * from "./associate-sales-channels-with-publishable-keys" export * from "./link-sales-channels-to-publishable-key"
export * from "./create-api-keys" export * from "./create-api-keys"
export * from "./delete-api-keys" export * from "./delete-api-keys"
export * from "./detach-sales-channels-from-publishable-keys"
export * from "./revoke-api-keys" export * from "./revoke-api-keys"
export * from "./update-api-keys" export * from "./update-api-keys"
export * from "./validate-sales-channel-exists" export * from "./validate-sales-channel-exists"
@@ -0,0 +1,62 @@
import { Modules } from "@medusajs/modules-sdk"
import { LinkWorkflowInput } from "@medusajs/types/src"
import { ContainerRegistrationKeys, promiseAll } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export const linkSalesChannelsToApiKeyStepId = "link-sales-channels-to-api-key"
export const linkSalesChannelsToApiKeyStep = createStep(
linkSalesChannelsToApiKeyStepId,
async (input: LinkWorkflowInput, { container }) => {
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
if (!input || (!input.add?.length && !input.remove?.length)) {
return
}
const linksToCreate = (input.add ?? []).map((salesChannelId) => {
return {
[Modules.API_KEY]: {
publishable_key_id: input.id,
},
[Modules.SALES_CHANNEL]: {
sales_channel_id: salesChannelId,
},
}
})
const linksToDismiss = (input.remove ?? []).map((salesChannelId) => {
return {
[Modules.API_KEY]: {
publishable_key_id: input.id,
},
[Modules.SALES_CHANNEL]: {
sales_channel_id: salesChannelId,
},
}
})
const promises: Promise<any>[] = []
if (linksToCreate.length) {
promises.push(remoteLink.create(linksToCreate))
}
if (linksToDismiss.length) {
promises.push(remoteLink.dismiss(linksToDismiss))
}
await promiseAll(promises)
return new StepResponse(void 0, { linksToCreate, linksToDismiss })
},
async (prevData, { container }) => {
if (!prevData) {
return
}
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
if (prevData.linksToCreate.length) {
await remoteLink.dismiss(prevData.linksToCreate)
}
if (prevData.linksToDismiss.length) {
await remoteLink.create(prevData.linksToDismiss)
}
}
)
@@ -1,31 +0,0 @@
import {
WorkflowData,
createWorkflow,
transform,
} from "@medusajs/workflows-sdk"
import {
associateApiKeysWithSalesChannelsStep,
validateSalesChannelsExistStep,
} from "../steps"
type WorkflowInput = {
data: {
api_key_id: string
sales_channel_ids: string[]
}[]
}
export const addSalesChannelsToApiKeyWorkflowId =
"add-sales-channels-to-api-key"
export const addSalesChannelsToApiKeyWorkflow = createWorkflow(
addSalesChannelsToApiKeyWorkflowId,
(input: WorkflowData<WorkflowInput>) => {
const salesChannelIds = transform(input.data, (data) =>
data.map((d) => d.sales_channel_ids).flat()
)
validateSalesChannelsExistStep({
sales_channel_ids: salesChannelIds,
})
associateApiKeysWithSalesChannelsStep({ links: input.data })
}
)
@@ -2,5 +2,4 @@ export * from "./create-api-keys"
export * from "./delete-api-keys" export * from "./delete-api-keys"
export * from "./update-api-keys" export * from "./update-api-keys"
export * from "./revoke-api-keys" export * from "./revoke-api-keys"
export * from "./add-sales-channels-to-publishable-key" export * from "./link-sales-channels-to-publishable-key"
export * from "./remove-sales-channels-from-publishable-key"
@@ -0,0 +1,19 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import {
linkSalesChannelsToApiKeyStep,
validateSalesChannelsExistStep,
} from "../steps"
import { LinkWorkflowInput } from "@medusajs/types/src"
export const linkSalesChannelsToApiKeyWorkflowId =
"link-sales-channels-to-api-key"
export const linkSalesChannelsToApiKeyWorkflow = createWorkflow(
linkSalesChannelsToApiKeyWorkflowId,
(input: WorkflowData<LinkWorkflowInput>) => {
validateSalesChannelsExistStep({
sales_channel_ids: input.add ?? [],
})
linkSalesChannelsToApiKeyStep(input)
}
)
@@ -1,18 +0,0 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { detachApiKeysWithSalesChannelsStep } from "../steps/detach-sales-channels-from-publishable-keys"
type WorkflowInput = {
data: {
api_key_id: string
sales_channel_ids: string[]
}[]
}
export const removeSalesChannelsFromApiKeyWorkflowId =
"remove-sales-channels-from-api-key"
export const removeSalesChannelsFromApiKeyWorkflow = createWorkflow(
removeSalesChannelsFromApiKeyWorkflowId,
(input: WorkflowData<WorkflowInput>) => {
detachApiKeysWithSalesChannelsStep({ links: input.data })
}
)
@@ -1,29 +0,0 @@
import { GroupCustomerPair, ICustomerModuleService } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
export const createCustomerGroupCustomersStepId =
"create-customer-group-customers"
export const createCustomerGroupCustomersStep = createStep(
createCustomerGroupCustomersStepId,
async (data: GroupCustomerPair[], { container }) => {
const service = container.resolve<ICustomerModuleService>(
ModuleRegistrationName.CUSTOMER
)
const groupPairs = await service.addCustomerToGroup(data)
return new StepResponse(groupPairs, data)
},
async (groupPairs, { container }) => {
if (!groupPairs?.length) {
return
}
const service = container.resolve<ICustomerModuleService>(
ModuleRegistrationName.CUSTOMER
)
await service.removeCustomerFromGroup(groupPairs)
}
)
@@ -1,5 +1,4 @@
export * from "./update-customer-groups" export * from "./update-customer-groups"
export * from "./delete-customer-groups" export * from "./delete-customer-groups"
export * from "./create-customer-groups" export * from "./create-customer-groups"
export * from "./create-customer-group-customers" export * from "./link-customers-customer-group"
export * from "./delete-customer-group-customers"
@@ -0,0 +1,56 @@
import { ICustomerModuleService } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { LinkWorkflowInput } from "@medusajs/types/src"
import { promiseAll } from "@medusajs/utils"
export const linkCustomersToCustomerGroupStepId =
"link-customers-to-customer-group"
export const linkCustomersToCustomerGroupStep = createStep(
linkCustomersToCustomerGroupStepId,
async (data: LinkWorkflowInput, { container }) => {
const service = container.resolve<ICustomerModuleService>(
ModuleRegistrationName.CUSTOMER
)
const toAdd = (data.add ?? []).map((customerId) => {
return {
customer_id: customerId,
customer_group_id: data.id,
}
})
const toRemove = (data.remove ?? []).map((customerId) => {
return {
customer_id: customerId,
customer_group_id: data.id,
}
})
const promises: Promise<any>[] = []
if (toAdd.length) {
promises.push(service.addCustomerToGroup(toAdd))
}
if (toRemove.length) {
promises.push(service.removeCustomerFromGroup(toRemove))
}
await promiseAll(promises)
return new StepResponse(void 0, { toAdd, toRemove })
},
async (prevData, { container }) => {
if (!prevData) {
return
}
const service = container.resolve<ICustomerModuleService>(
ModuleRegistrationName.CUSTOMER
)
if (prevData.toAdd.length) {
await service.removeCustomerFromGroup(prevData.toAdd)
}
if (prevData.toRemove.length) {
await service.addCustomerToGroup(prevData.toRemove)
}
}
)
@@ -1,14 +0,0 @@
import { GroupCustomerPair } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { createCustomerGroupCustomersStep } from "../steps"
type WorkflowInput = { groupCustomers: GroupCustomerPair[] }
export const createCustomerGroupCustomersWorkflowId =
"create-customer-group-customers"
export const createCustomerGroupCustomersWorkflow = createWorkflow(
createCustomerGroupCustomersWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<{ id: string }[]> => {
return createCustomerGroupCustomersStep(input.groupCustomers)
}
)
@@ -1,14 +0,0 @@
import { GroupCustomerPair } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { deleteCustomerGroupCustomersStep } from "../steps"
type WorkflowInput = { groupCustomers: GroupCustomerPair[] }
export const deleteCustomerGroupCustomersWorkflowId =
"delete-customer-group-customers"
export const deleteCustomerGroupCustomersWorkflow = createWorkflow(
deleteCustomerGroupCustomersWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
return deleteCustomerGroupCustomersStep(input.groupCustomers)
}
)
@@ -1,5 +1,4 @@
export * from "./update-customer-groups" export * from "./update-customer-groups"
export * from "./delete-customer-groups" export * from "./delete-customer-groups"
export * from "./create-customer-groups" export * from "./create-customer-groups"
export * from "./create-customer-group-customers" export * from "./link-customers-customer-group"
export * from "./delete-customer-group-customers"
@@ -0,0 +1,12 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { linkCustomersToCustomerGroupStep } from "../steps"
import { LinkWorkflowInput } from "@medusajs/types/src"
export const linkCustomersToCustomerGroupWorkflowId =
"link-customers-to-customer-group"
export const linkCustomersToCustomerGroupWorkflow = createWorkflow(
linkCustomersToCustomerGroupWorkflowId,
(input: WorkflowData<LinkWorkflowInput>): WorkflowData<void> => {
return linkCustomersToCustomerGroupStep(input)
}
)
@@ -1,13 +1,13 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IProductModuleService } from "@medusajs/types" import { IProductModuleService } from "@medusajs/types"
import { BatchLinkProductsToCollectionDTO } from "@medusajs/types/src" import { LinkWorkflowInput } from "@medusajs/types/src"
import { StepResponse, createStep } from "@medusajs/workflows-sdk" import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export const batchLinkProductsToCollectionStepId = export const batchLinkProductsToCollectionStepId =
"batch-link-products-to-collection" "batch-link-products-to-collection"
export const batchLinkProductsToCollectionStep = createStep( export const batchLinkProductsToCollectionStep = createStep(
batchLinkProductsToCollectionStepId, batchLinkProductsToCollectionStepId,
async (data: BatchLinkProductsToCollectionDTO, { container }) => { async (data: LinkWorkflowInput, { container }) => {
const service = container.resolve<IProductModuleService>( const service = container.resolve<IProductModuleService>(
ModuleRegistrationName.PRODUCT ModuleRegistrationName.PRODUCT
) )
@@ -2,33 +2,33 @@ import { StepResponse, createStep } from "@medusajs/workflows-sdk"
import { deleteProductVariantsWorkflow } from "../workflows/delete-product-variants" import { deleteProductVariantsWorkflow } from "../workflows/delete-product-variants"
import { createProductVariantsWorkflow } from "../workflows/create-product-variants" import { createProductVariantsWorkflow } from "../workflows/create-product-variants"
import { updateProductVariantsWorkflow } from "../workflows/update-product-variants" import { updateProductVariantsWorkflow } from "../workflows/update-product-variants"
import { PricingTypes, ProductTypes } from "@medusajs/types" import {
BatchWorkflowInput,
type BatchProductVariantsInput = { CreateProductVariantWorkflowInputDTO,
create: (ProductTypes.CreateProductVariantDTO & { UpdateProductVariantWorkflowInputDTO,
prices?: PricingTypes.CreateMoneyAmountDTO[] } from "@medusajs/types"
})[]
update: (ProductTypes.UpsertProductVariantDTO & {
prices?: PricingTypes.CreateMoneyAmountDTO[]
})[]
delete: string[]
}
export const batchProductVariantsStepId = "batch-product-variants" export const batchProductVariantsStepId = "batch-product-variants"
export const batchProductVariantsStep = createStep( export const batchProductVariantsStep = createStep(
batchProductVariantsStepId, batchProductVariantsStepId,
async (data: BatchProductVariantsInput, { container }) => { async (
data: BatchWorkflowInput<
CreateProductVariantWorkflowInputDTO,
UpdateProductVariantWorkflowInputDTO
>,
{ container }
) => {
const { transaction: createTransaction, result: created } = const { transaction: createTransaction, result: created } =
await createProductVariantsWorkflow(container).run({ await createProductVariantsWorkflow(container).run({
input: { product_variants: data.create }, input: { product_variants: data.create ?? [] },
}) })
const { transaction: updateTransaction, result: updated } = const { transaction: updateTransaction, result: updated } =
await updateProductVariantsWorkflow(container).run({ await updateProductVariantsWorkflow(container).run({
input: { product_variants: data.update }, input: { product_variants: data.update ?? [] },
}) })
const { transaction: deleteTransaction } = const { transaction: deleteTransaction } =
await deleteProductVariantsWorkflow(container).run({ await deleteProductVariantsWorkflow(container).run({
input: { ids: data.delete }, input: { ids: data.delete ?? [] },
}) })
return new StepResponse( return new StepResponse(
@@ -36,7 +36,7 @@ export const batchProductVariantsStep = createStep(
created, created,
updated, updated,
deleted: { deleted: {
ids: data.delete, ids: data.delete ?? [],
object: "product_variant", object: "product_variant",
deleted: true, deleted: true,
}, },
@@ -2,37 +2,34 @@ import { StepResponse, createStep } from "@medusajs/workflows-sdk"
import { createProductsWorkflow } from "../workflows/create-products" import { createProductsWorkflow } from "../workflows/create-products"
import { updateProductsWorkflow } from "../workflows/update-products" import { updateProductsWorkflow } from "../workflows/update-products"
import { deleteProductsWorkflow } from "../workflows/delete-products" import { deleteProductsWorkflow } from "../workflows/delete-products"
import { PricingTypes, ProductTypes } from "@medusajs/types" import {
BatchWorkflowInput,
type WorkflowInput = { CreateProductWorkflowInputDTO,
create: (Omit<ProductTypes.CreateProductDTO, "variants"> & { UpdateProductWorkflowInputDTO,
sales_channels?: { id: string }[] } from "@medusajs/types"
variants?: (ProductTypes.CreateProductVariantDTO & {
prices?: PricingTypes.CreateMoneyAmountDTO[]
})[]
})[]
update: (ProductTypes.UpsertProductDTO & {
sales_channels?: { id: string }[]
})[]
delete: string[]
}
export const batchProductsStepId = "batch-products" export const batchProductsStepId = "batch-products"
export const batchProductsStep = createStep( export const batchProductsStep = createStep(
batchProductsStepId, batchProductsStepId,
async (data: WorkflowInput, { container }) => { async (
data: BatchWorkflowInput<
CreateProductWorkflowInputDTO,
UpdateProductWorkflowInputDTO
>,
{ container }
) => {
const { transaction: createTransaction, result: created } = const { transaction: createTransaction, result: created } =
await createProductsWorkflow(container).run({ await createProductsWorkflow(container).run({
input: { products: data.create }, input: { products: data.create ?? [] },
}) })
const { transaction: updateTransaction, result: updated } = const { transaction: updateTransaction, result: updated } =
await updateProductsWorkflow(container).run({ await updateProductsWorkflow(container).run({
input: { products: data.update }, input: { products: data.update ?? [] },
}) })
const { transaction: deleteTransaction } = await deleteProductsWorkflow( const { transaction: deleteTransaction } = await deleteProductsWorkflow(
container container
).run({ ).run({
input: { ids: data.delete }, input: { ids: data.delete ?? [] },
}) })
return new StepResponse( return new StepResponse(
@@ -40,7 +37,7 @@ export const batchProductsStep = createStep(
created, created,
updated, updated,
deleted: { deleted: {
ids: data.delete, ids: data.delete ?? [],
object: "product", object: "product",
deleted: true, deleted: true,
}, },
@@ -1,14 +1,12 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { BatchLinkProductsToCollectionDTO } from "@medusajs/types/src" import { LinkWorkflowInput } from "@medusajs/types/src"
import { batchLinkProductsToCollectionStep } from "../steps/batch-link-products-collection" import { batchLinkProductsToCollectionStep } from "../steps/batch-link-products-collection"
export const batchLinkProductsToCollectionWorkflowId = export const batchLinkProductsToCollectionWorkflowId =
"batch-link-products-to-collection" "batch-link-products-to-collection"
export const batchLinkProductsToCollectionWorkflow = createWorkflow( export const batchLinkProductsToCollectionWorkflow = createWorkflow(
batchLinkProductsToCollectionWorkflowId, batchLinkProductsToCollectionWorkflowId,
( (input: WorkflowData<LinkWorkflowInput>): WorkflowData<void> => {
input: WorkflowData<BatchLinkProductsToCollectionDTO>
): WorkflowData<void> => {
return batchLinkProductsToCollectionStep(input) return batchLinkProductsToCollectionStep(input)
} }
) )
@@ -1,33 +1,24 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { batchProductVariantsStep } from "../steps/batch-product-variants" import { batchProductVariantsStep } from "../steps/batch-product-variants"
import { PricingTypes, ProductTypes } from "@medusajs/types" import {
BatchWorkflowInput,
type BatchProductVariantsInput = { BatchWorkflowOutput,
create: (ProductTypes.CreateProductVariantDTO & { ProductTypes,
prices?: PricingTypes.CreateMoneyAmountDTO[] UpdateProductVariantWorkflowInputDTO,
})[] CreateProductVariantWorkflowInputDTO,
update: (ProductTypes.UpsertProductVariantDTO & { } from "@medusajs/types"
prices?: PricingTypes.CreateMoneyAmountDTO[]
})[]
delete: string[]
}
type BatchProductVariantsOutput = {
created: ProductTypes.ProductVariantDTO[]
updated: ProductTypes.ProductVariantDTO[]
deleted: {
ids: string[]
object: string
deleted: boolean
}
}
export const batchProductVariantsWorkflowId = "batch-product-variants" export const batchProductVariantsWorkflowId = "batch-product-variants"
export const batchProductVariantsWorkflow = createWorkflow( export const batchProductVariantsWorkflow = createWorkflow(
batchProductVariantsWorkflowId, batchProductVariantsWorkflowId,
( (
input: WorkflowData<BatchProductVariantsInput> input: WorkflowData<
): WorkflowData<BatchProductVariantsOutput> => { BatchWorkflowInput<
CreateProductVariantWorkflowInputDTO,
UpdateProductVariantWorkflowInputDTO
>
>
): WorkflowData<BatchWorkflowOutput<ProductTypes.ProductVariantDTO>> => {
return batchProductVariantsStep(input) return batchProductVariantsStep(input)
} }
) )
@@ -1,34 +1,24 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { batchProductsStep } from "../steps/batch-products" import { batchProductsStep } from "../steps/batch-products"
import { PricingTypes, ProductTypes } from "@medusajs/types" import {
ProductTypes,
type WorkflowInput = { BatchWorkflowInput,
create: (Omit<ProductTypes.CreateProductDTO, "variants"> & { CreateProductWorkflowInputDTO,
sales_channels?: { id: string }[] UpdateProductWorkflowInputDTO,
variants?: (ProductTypes.CreateProductVariantDTO & { } from "@medusajs/types"
prices?: PricingTypes.CreateMoneyAmountDTO[] import { BatchWorkflowOutput } from "@medusajs/types/src"
})[]
})[]
update: (ProductTypes.UpsertProductDTO & {
sales_channels?: { id: string }[]
})[]
delete: string[]
}
type BatchProductsOutput = {
created: ProductTypes.ProductDTO[]
updated: ProductTypes.ProductDTO[]
deleted: {
ids: string[]
object: string
deleted: boolean
}
}
export const batchProductsWorkflowId = "batch-products" export const batchProductsWorkflowId = "batch-products"
export const batchProductsWorkflow = createWorkflow( export const batchProductsWorkflow = createWorkflow(
batchProductsWorkflowId, batchProductsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<BatchProductsOutput> => { (
input: WorkflowData<
BatchWorkflowInput<
CreateProductWorkflowInputDTO,
UpdateProductWorkflowInputDTO
>
>
): WorkflowData<BatchWorkflowOutput<ProductTypes.ProductDTO>> => {
return batchProductsStep(input) return batchProductsStep(input)
} }
) )
@@ -8,16 +8,10 @@ import { createProductsStep } from "../steps/create-products"
import { createVariantPricingLinkStep } from "../steps/create-variant-pricing-link" import { createVariantPricingLinkStep } from "../steps/create-variant-pricing-link"
import { createPriceSetsStep } from "../../pricing" import { createPriceSetsStep } from "../../pricing"
import { associateProductsWithSalesChannelsStep } from "../../sales-channel" import { associateProductsWithSalesChannelsStep } from "../../sales-channel"
import { CreateProductWorkflowInputDTO } from "@medusajs/types/src"
// TODO: We should have separate types here as input, not the module DTO. Eg. the HTTP request that we are handling
// has different data than the DTO, so that needs to be represented differently.
type WorkflowInput = { type WorkflowInput = {
products: (Omit<ProductTypes.CreateProductDTO, "variants"> & { products: CreateProductWorkflowInputDTO[]
sales_channels?: { id: string }[]
variants?: (ProductTypes.CreateProductVariantDTO & {
prices?: PricingTypes.CreateMoneyAmountDTO[]
})[]
})[]
} }
export const createProductsWorkflowId = "create-products" export const createProductsWorkflowId = "create-products"
@@ -6,38 +6,32 @@ import { Modules } from "@medusajs/modules-sdk"
interface StepInput { interface StepInput {
links: { links: {
sales_channel_id: string sales_channel_id: string
location_ids: string[] location_id: string
}[] }[]
} }
export const associateLocationsWithChannelStepId = export const associateLocationsWithSalesChannelsStepId =
"associate-locations-with-channel-step" "associate-locations-with-sales-channels-step"
export const associateLocationsWithChannelStep = createStep( export const associateLocationsWithSalesChannelsStep = createStep(
associateLocationsWithChannelStepId, associateLocationsWithSalesChannelsStepId,
async (data: StepInput, { container }) => { async (data: StepInput, { container }) => {
if (!data.links.length) { if (!data.links?.length) {
return new StepResponse([], []) return new StepResponse([], [])
} }
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK) const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
const links = data.links.map((link) => {
const links = data.links return {
.map((link) => { [Modules.SALES_CHANNEL]: {
return link.location_ids.map((id) => { sales_channel_id: link.sales_channel_id,
return { },
[Modules.SALES_CHANNEL]: { [Modules.STOCK_LOCATION]: {
sales_channel_id: link.sales_channel_id, stock_location_id: link.location_id,
}, },
[Modules.STOCK_LOCATION]: { }
stock_location_id: id, })
},
}
})
})
.flat()
const createdLinks = await remoteLink.create(links) const createdLinks = await remoteLink.create(links)
return new StepResponse(createdLinks, links) return new StepResponse(createdLinks, links)
}, },
async (links, { container }) => { async (links, { container }) => {
@@ -46,7 +40,6 @@ export const associateLocationsWithChannelStep = createStep(
} }
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK) const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
await remoteLink.dismiss(links) await remoteLink.dismiss(links)
} }
) )
@@ -14,7 +14,7 @@ export const associateProductsWithSalesChannelsStepId =
export const associateProductsWithSalesChannelsStep = createStep( export const associateProductsWithSalesChannelsStep = createStep(
associateProductsWithSalesChannelsStepId, associateProductsWithSalesChannelsStepId,
async (input: StepInput, { container }) => { async (input: StepInput, { container }) => {
if (!input.links.length) { if (!input.links?.length) {
return new StepResponse([], []) return new StepResponse([], [])
} }
@@ -0,0 +1,48 @@
import { Modules, RemoteLink } from "@medusajs/modules-sdk"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
import { ContainerRegistrationKeys } from "@medusajs/utils"
interface StepInput {
links: {
sales_channel_id: string
location_id: string
}[]
}
export const detachLocationsFromSalesChannelsStepId =
"detach-locations-from-sales-channels"
export const detachLocationsFromSalesChannelsStep = createStep(
detachLocationsFromSalesChannelsStepId,
async (data: StepInput, { container }) => {
if (!data.links?.length) {
return new StepResponse([], [])
}
const remoteLink = container.resolve<RemoteLink>(
ContainerRegistrationKeys.REMOTE_LINK
)
const links = data.links.map((link) => {
return {
[Modules.SALES_CHANNEL]: {
sales_channel_id: link.sales_channel_id,
},
[Modules.STOCK_LOCATION]: {
stock_location_id: link.location_id,
},
}
})
await remoteLink.dismiss(links)
return new StepResponse(void 0, links)
},
async (links, { container }) => {
if (!links?.length) {
return
}
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
await remoteLink.create(links)
}
)
@@ -14,7 +14,7 @@ export const detachProductsFromSalesChannelsStepId =
export const detachProductsFromSalesChannelsStep = createStep( export const detachProductsFromSalesChannelsStep = createStep(
detachProductsFromSalesChannelsStepId, detachProductsFromSalesChannelsStepId,
async (input: StepInput, { container }) => { async (input: StepInput, { container }) => {
if (!input.links.length) { if (!input.links?.length) {
return new StepResponse(void 0, []) return new StepResponse(void 0, [])
} }
@@ -4,5 +4,5 @@ export * from "./create-sales-channels"
export * from "./delete-sales-channels" export * from "./delete-sales-channels"
export * from "./detach-products-from-sales-channels" export * from "./detach-products-from-sales-channels"
export * from "./update-sales-channels" export * from "./update-sales-channels"
export * from "./associate-locations-with-channel" export * from "./associate-locations-with-channels"
export * from "./remove-locations-from-channels" export * from "./detach-locations-from-channels"
@@ -1,71 +0,0 @@
import { Modules, RemoteLink } from "@medusajs/modules-sdk"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
import { ContainerRegistrationKeys } from "@medusajs/utils"
export const removeLocationsFromSalesChannelStepId =
"remove-locations-from-sales-channel"
export const removeLocationsFromSalesChannelStep = createStep(
removeLocationsFromSalesChannelStepId,
async (
data: {
sales_channel_id: string
location_ids: string[]
}[],
{ container }
) => {
if (!data.length) {
return new StepResponse([], [])
}
const remoteLink = container.resolve<RemoteLink>(
ContainerRegistrationKeys.REMOTE_LINK
)
const linkModule = remoteLink.getLinkModule(
Modules.SALES_CHANNEL,
"sales_channel_id",
Modules.STOCK_LOCATION,
"stock_location_id"
)
if (!linkModule) {
return new StepResponse([], [])
}
const links = data
.map((d) =>
d.location_ids.map((locId) => ({
sales_channel_id: d.sales_channel_id,
stock_location_id: locId,
}))
)
.flat()
await linkModule.softDelete(links)
return new StepResponse(void 0, links)
},
async (links, { container }) => {
if (!links?.length) {
return
}
const remoteLink = container.resolve<RemoteLink>(
ContainerRegistrationKeys.REMOTE_LINK
)
const linkModule = remoteLink.getLinkModule(
Modules.SALES_CHANNEL,
"sales_channel_id",
Modules.STOCK_LOCATION,
"stock_location_id"
)
if (!linkModule) {
return
}
await linkModule.restore(links)
}
)
@@ -1,20 +0,0 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { SalesChannelDTO } from "@medusajs/types"
import { associateLocationsWithChannelStep } from "../steps"
interface WorkflowInput {
data: {
sales_channel_id: string
location_ids: string[]
}[]
}
export const addLocationsToSalesChannelWorkflowId =
"add-locations-to-sales-channel"
export const addLocationsToSalesChannelWorkflow = createWorkflow(
addLocationsToSalesChannelWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<SalesChannelDTO[]> => {
return associateLocationsWithChannelStep({ links: input.data })
}
)
@@ -1,33 +0,0 @@
import { SalesChannelDTO } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { associateProductsWithSalesChannelsStep } from "../steps/associate-products-with-channels"
import { transform } from "@medusajs/workflows-sdk"
type WorkflowInput = {
data: {
sales_channel_id: string
product_ids: string[]
}[]
}
export const addProductsToSalesChannelsWorkflowId =
"add-products-to-sales-channels"
export const addProductsToSalesChannelsWorkflow = createWorkflow(
addProductsToSalesChannelsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<SalesChannelDTO[]> => {
const links = transform({ input }, (data) => {
return data.input.data
.map(({ sales_channel_id, product_ids }) => {
return product_ids.map((product_id) => {
return {
sales_channel_id,
product_id,
}
})
})
.flat()
})
return associateProductsWithSalesChannelsStep({ links })
}
)
@@ -1,7 +1,4 @@
export * from "./add-products-to-sales-channels" export * from "./link-products-to-sales-channel"
export * from "./create-sales-channels" export * from "./create-sales-channels"
export * from "./delete-sales-channels" export * from "./delete-sales-channels"
export * from "./remove-products-from-sales-channels"
export * from "./update-sales-channels" export * from "./update-sales-channels"
export * from "./add-locations-to-sales-channel"
export * from "./remove-locations-from-sales-channel"
@@ -0,0 +1,29 @@
import { LinkWorkflowInput } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { associateProductsWithSalesChannelsStep } from "../steps/associate-products-with-channels"
import { transform } from "@medusajs/workflows-sdk"
import { detachProductsFromSalesChannelsStep } from "../steps"
export const linkProductsToSalesChannelWorkflowId =
"link-products-to-sales-channel"
export const linkProductsToSalesChannelWorkflow = createWorkflow(
linkProductsToSalesChannelWorkflowId,
(input: WorkflowData<LinkWorkflowInput>): WorkflowData<void> => {
const toAdd = transform({ input }, (data) => {
return data.input.add?.map((productId) => ({
sales_channel_id: data.input.id,
product_id: productId,
}))
})
const toRemove = transform({ input }, (data) => {
return data.input.remove?.map((productId) => ({
sales_channel_id: data.input.id,
product_id: productId,
}))
})
associateProductsWithSalesChannelsStep({ links: toAdd })
detachProductsFromSalesChannelsStep({ links: toRemove })
}
)
@@ -1,19 +0,0 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { removeLocationsFromSalesChannelStep } from "../steps"
interface WorkflowInput {
data: {
sales_channel_id: string
location_ids: string[]
}[]
}
export const removeLocationsFromSalesChannelWorkflowId =
"remove-locations-from-sales-channel"
export const removeLocationsFromSalesChannelWorkflow = createWorkflow(
removeLocationsFromSalesChannelWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
removeLocationsFromSalesChannelStep(input.data)
}
)
@@ -1,33 +0,0 @@
import { SalesChannelDTO } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { detachProductsFromSalesChannelsStep } from "../steps/detach-products-from-sales-channels"
import { transform } from "@medusajs/workflows-sdk"
type WorkflowInput = {
data: {
sales_channel_id: string
product_ids: string[]
}[]
}
export const removeProductsFromSalesChannelsWorkflowId =
"remove-products-from-sales-channels"
export const removeProductsFromSalesChannelsWorkflow = createWorkflow(
removeProductsFromSalesChannelsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<SalesChannelDTO[]> => {
const links = transform({ input }, (data) => {
return data.input.data
.map(({ sales_channel_id, product_ids }) => {
return product_ids.map((product_id) => {
return {
sales_channel_id,
product_id,
}
})
})
.flat()
})
return detachProductsFromSalesChannelsStep({ links })
}
)
@@ -2,3 +2,4 @@ export * from "./create-location-fulfillment-set"
export * from "./create-stock-locations" export * from "./create-stock-locations"
export * from "./delete-stock-locations" export * from "./delete-stock-locations"
export * from "./update-stock-locations" export * from "./update-stock-locations"
export * from "./link-sales-channels-to-stock-location"
@@ -0,0 +1,31 @@
import { LinkWorkflowInput } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { transform } from "@medusajs/workflows-sdk"
import {
associateLocationsWithSalesChannelsStep,
detachLocationsFromSalesChannelsStep,
} from "../../sales-channel"
export const linkSalesChannelsToStockLocationWorkflowId =
"link-sales-channels-to-stock-location"
export const linkSalesChannelsToStockLocationWorkflow = createWorkflow(
linkSalesChannelsToStockLocationWorkflowId,
(input: WorkflowData<LinkWorkflowInput>): WorkflowData<void> => {
const toAdd = transform({ input }, (data) => {
return data.input.add?.map((salesChannelId) => ({
sales_channel_id: salesChannelId,
location_id: data.input.id,
}))
})
const toRemove = transform({ input }, (data) => {
return data.input.remove?.map((salesChannelId) => ({
sales_channel_id: salesChannelId,
location_id: data.input.id,
}))
})
associateLocationsWithSalesChannelsStep({ links: toAdd })
detachLocationsFromSalesChannelsStep({ links: toRemove })
}
)
@@ -1,83 +0,0 @@
import {
addSalesChannelsToApiKeyWorkflow,
removeSalesChannelsFromApiKeyWorkflow,
} from "@medusajs/core-flows"
import { ApiKeyType, MedusaError } from "@medusajs/utils"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../../../types/routing"
import { AdminApiKeySalesChannelType } from "../../../validators"
import { BatchMethodRequest } from "@medusajs/types"
import { refetchApiKey } from "../../../helpers"
export const POST = async (
req: AuthenticatedMedusaRequest<
BatchMethodRequest<AdminApiKeySalesChannelType, AdminApiKeySalesChannelType>
>,
res: MedusaResponse
) => {
const { create, delete: toDelete } = req.validatedBody
const apiKey = await refetchApiKey(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
if (apiKey.type !== ApiKeyType.PUBLISHABLE) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Sales channels can only be associated with publishable API keys"
)
}
if (create?.length) {
const workflowInput = {
data: [
{
api_key_id: req.params.id,
sales_channel_ids: create ?? [],
},
],
}
const { errors } = await addSalesChannelsToApiKeyWorkflow(req.scope).run({
input: workflowInput,
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
}
if (toDelete?.length) {
const workflowInput = {
data: [
{
api_key_id: req.params.id,
sales_channel_ids: toDelete,
},
],
}
const { errors } = await removeSalesChannelsFromApiKeyWorkflow(
req.scope
).run({
input: workflowInput,
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
}
const newApiKey = await refetchApiKey(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ api_key: newApiKey })
}
@@ -0,0 +1,44 @@
import { ApiKeyType, MedusaError } from "@medusajs/utils"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../../types/routing"
import { refetchApiKey } from "../../helpers"
import { LinkMethodRequest } from "@medusajs/types/src"
import { linkSalesChannelsToApiKeyWorkflow } from "@medusajs/core-flows"
export const POST = async (
req: AuthenticatedMedusaRequest<LinkMethodRequest>,
res: MedusaResponse
) => {
const { add, remove } = req.validatedBody
const apiKey = await refetchApiKey(req.params.id, req.scope, ["id", "type"])
if (apiKey.type !== ApiKeyType.PUBLISHABLE) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Sales channels can only be associated with publishable API keys"
)
}
const { errors } = await linkSalesChannelsToApiKeyWorkflow(req.scope).run({
input: {
id: req.params.id,
add,
remove,
},
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const updatedApiKey = await refetchApiKey(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ api_key: updatedApiKey })
}
@@ -4,7 +4,6 @@ import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
import { authenticate } from "../../../utils/authenticate-middleware" import { authenticate } from "../../../utils/authenticate-middleware"
import { validateAndTransformQuery } from "../../utils/validate-query" import { validateAndTransformQuery } from "../../utils/validate-query"
import { import {
AdminApiKeySalesChannel,
AdminCreateApiKey, AdminCreateApiKey,
AdminGetApiKeyParams, AdminGetApiKeyParams,
AdminGetApiKeysParams, AdminGetApiKeysParams,
@@ -12,7 +11,7 @@ import {
AdminUpdateApiKey, AdminUpdateApiKey,
} from "./validators" } from "./validators"
import { validateAndTransformBody } from "../../utils/validate-body" import { validateAndTransformBody } from "../../utils/validate-body"
import { createBatchBody } from "../../utils/validators" import { createLinkBody } from "../../utils/validators"
export const adminApiKeyRoutesMiddlewares: MiddlewareRoute[] = [ export const adminApiKeyRoutesMiddlewares: MiddlewareRoute[] = [
{ {
@@ -79,11 +78,9 @@ export const adminApiKeyRoutesMiddlewares: MiddlewareRoute[] = [
}, },
{ {
method: ["POST"], method: ["POST"],
matcher: "/admin/api-keys/:id/sales-channels/batch", matcher: "/admin/api-keys/:id/sales-channels",
middlewares: [ middlewares: [
validateAndTransformBody( validateAndTransformBody(createLinkBody()),
createBatchBody(AdminApiKeySalesChannel, AdminApiKeySalesChannel)
),
validateAndTransformQuery( validateAndTransformQuery(
AdminGetApiKeyParams, AdminGetApiKeyParams,
QueryConfig.retrieveTransformQueryConfig QueryConfig.retrieveTransformQueryConfig
@@ -41,8 +41,3 @@ export type AdminRevokeApiKeyType = z.infer<typeof AdminRevokeApiKey>
export const AdminRevokeApiKey = z.object({ export const AdminRevokeApiKey = z.object({
revoke_in: z.number().optional(), revoke_in: z.number().optional(),
}) })
export type AdminApiKeySalesChannelType = z.infer<
typeof AdminApiKeySalesChannel
>
export const AdminApiKeySalesChannel = z.string()
@@ -1,66 +0,0 @@
import { AdminCustomerGroupResponse, BatchMethodRequest } from "@medusajs/types"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../../../types/routing"
import { AdminSetCustomersCustomerGroupType } from "../../../validators"
import {
createCustomerGroupCustomersWorkflow,
deleteCustomerGroupCustomersWorkflow,
} from "@medusajs/core-flows"
import { refetchCustomerGroup } from "../../../helpers"
export const POST = async (
req: AuthenticatedMedusaRequest<
BatchMethodRequest<
AdminSetCustomersCustomerGroupType,
AdminSetCustomersCustomerGroupType
>
>,
res: MedusaResponse<AdminCustomerGroupResponse>
) => {
const { id } = req.params
const { create, delete: toDelete } = req.validatedBody
if (create?.length) {
const createCustomers = createCustomerGroupCustomersWorkflow(req.scope)
const { errors } = await createCustomers.run({
input: {
groupCustomers: create.map((c) => ({
customer_id: c,
customer_group_id: id,
})),
},
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
}
if (toDelete?.length) {
const deleteCustomers = deleteCustomerGroupCustomersWorkflow(req.scope)
const { errors } = await deleteCustomers.run({
input: {
groupCustomers: toDelete.map((c) => ({
customer_id: c,
customer_group_id: id,
})),
},
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
}
const customerGroup = await refetchCustomerGroup(
id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ customer_group: customerGroup })
}
@@ -0,0 +1,37 @@
import { linkCustomersToCustomerGroupWorkflow } from "@medusajs/core-flows"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../../types/routing"
import { LinkMethodRequest } from "@medusajs/types/src"
import { refetchCustomerGroup } from "../../helpers"
export const POST = async (
req: AuthenticatedMedusaRequest<LinkMethodRequest>,
res: MedusaResponse
) => {
const { id } = req.params
const { add, remove } = req.validatedBody
const workflow = linkCustomersToCustomerGroupWorkflow(req.scope)
const { errors } = await workflow.run({
input: {
id,
add,
remove,
},
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const customerGroup = await refetchCustomerGroup(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ customer_group: customerGroup })
}
@@ -6,11 +6,10 @@ import {
AdminCreateCustomerGroup, AdminCreateCustomerGroup,
AdminGetCustomerGroupParams, AdminGetCustomerGroupParams,
AdminGetCustomerGroupsParams, AdminGetCustomerGroupsParams,
AdminSetCustomersCustomerGroup,
AdminUpdateCustomerGroup, AdminUpdateCustomerGroup,
} from "./validators" } from "./validators"
import { validateAndTransformBody } from "../../utils/validate-body" import { validateAndTransformBody } from "../../utils/validate-body"
import { createBatchBody } from "../../utils/validators" import { createLinkBody } from "../../utils/validators"
export const adminCustomerGroupRoutesMiddlewares: MiddlewareRoute[] = [ export const adminCustomerGroupRoutesMiddlewares: MiddlewareRoute[] = [
{ {
@@ -62,14 +61,9 @@ export const adminCustomerGroupRoutesMiddlewares: MiddlewareRoute[] = [
}, },
{ {
method: ["POST"], method: ["POST"],
matcher: "/admin/customer-groups/:id/customers/batch", matcher: "/admin/customer-groups/:id/customers",
middlewares: [ middlewares: [
validateAndTransformBody( validateAndTransformBody(createLinkBody()),
createBatchBody(
AdminSetCustomersCustomerGroup,
AdminSetCustomersCustomerGroup
)
),
validateAndTransformQuery( validateAndTransformQuery(
AdminGetCustomerGroupParams, AdminGetCustomerGroupParams,
QueryConfig.retrieveTransformQueryConfig QueryConfig.retrieveTransformQueryConfig
@@ -66,8 +66,3 @@ export type AdminUpdateCustomerGroupType = z.infer<
export const AdminUpdateCustomerGroup = z.object({ export const AdminUpdateCustomerGroup = z.object({
name: z.string(), name: z.string(),
}) })
export type AdminSetCustomersCustomerGroupType = z.infer<
typeof AdminSetCustomersCustomerGroup
>
export const AdminSetCustomersCustomerGroup = z.string()
@@ -1,38 +0,0 @@
import { addProductsToSalesChannelsWorkflow } from "@medusajs/core-flows"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../../../../types/routing"
import { refetchSalesChannel } from "../../../../helpers"
import { AdminSetSalesChannelProductsBatchType } from "../../../../validators"
export const POST = async (
req: AuthenticatedMedusaRequest<AdminSetSalesChannelProductsBatchType>,
res: MedusaResponse
) => {
const workflowInput = {
data: [
{
sales_channel_id: req.params.id,
product_ids: req.validatedBody.product_ids,
},
],
}
const { errors } = await addProductsToSalesChannelsWorkflow(req.scope).run({
input: workflowInput,
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const salesChannel = await refetchSalesChannel(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ sales_channel: salesChannel })
}
@@ -1,39 +0,0 @@
import { removeProductsFromSalesChannelsWorkflow } from "@medusajs/core-flows"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../../../../types/routing"
import { AdminSetSalesChannelProductsBatchType } from "../../../../validators"
import { refetchSalesChannel } from "../../../../helpers"
export const POST = async (
req: AuthenticatedMedusaRequest<AdminSetSalesChannelProductsBatchType>,
res: MedusaResponse
) => {
const workflowInput = {
data: [
{
sales_channel_id: req.params.id,
product_ids: req.validatedBody.product_ids,
},
],
}
const { errors } = await removeProductsFromSalesChannelsWorkflow(
req.scope
).run({
input: workflowInput,
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const salesChannel = await refetchSalesChannel(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ sales_channel: salesChannel })
}
@@ -0,0 +1,37 @@
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../../types/routing"
import { LinkMethodRequest } from "@medusajs/types/src"
import { refetchSalesChannel } from "../../helpers"
import { linkProductsToSalesChannelWorkflow } from "@medusajs/core-flows"
export const POST = async (
req: AuthenticatedMedusaRequest<LinkMethodRequest>,
res: MedusaResponse
) => {
const { id } = req.params
const { add, remove } = req.validatedBody
const workflow = linkProductsToSalesChannelWorkflow(req.scope)
const { errors } = await workflow.run({
input: {
id,
add,
remove,
},
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const salesChannel = await refetchSalesChannel(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ sales_channel: salesChannel })
}
@@ -3,12 +3,12 @@ import { authenticate } from "../../../utils/authenticate-middleware"
import { maybeApplyLinkFilter } from "../../utils/maybe-apply-link-filter" import { maybeApplyLinkFilter } from "../../utils/maybe-apply-link-filter"
import { validateAndTransformBody } from "../../utils/validate-body" import { validateAndTransformBody } from "../../utils/validate-body"
import { validateAndTransformQuery } from "../../utils/validate-query" import { validateAndTransformQuery } from "../../utils/validate-query"
import { createLinkBody } from "../../utils/validators"
import * as QueryConfig from "./query-config" import * as QueryConfig from "./query-config"
import { import {
AdminCreateSalesChannel, AdminCreateSalesChannel,
AdminGetSalesChannelParams, AdminGetSalesChannelParams,
AdminGetSalesChannelsParams, AdminGetSalesChannelsParams,
AdminSetSalesChannelProductsBatch,
AdminUpdateSalesChannel, AdminUpdateSalesChannel,
} from "./validators" } from "./validators"
@@ -77,20 +77,9 @@ export const adminSalesChannelRoutesMiddlewares: MiddlewareRoute[] = [
}, },
{ {
method: ["POST"], method: ["POST"],
matcher: "/admin/sales-channels/:id/products/batch/add", matcher: "/admin/sales-channels/:id/products",
middlewares: [ middlewares: [
validateAndTransformBody(AdminSetSalesChannelProductsBatch), validateAndTransformBody(createLinkBody()),
validateAndTransformQuery(
AdminGetSalesChannelParams,
QueryConfig.retrieveTransformQueryConfig
),
],
},
{
method: ["POST"],
matcher: "/admin/sales-channels/:id/products/batch/remove",
middlewares: [
validateAndTransformBody(AdminSetSalesChannelProductsBatch),
validateAndTransformQuery( validateAndTransformQuery(
AdminGetSalesChannelParams, AdminGetSalesChannelParams,
QueryConfig.retrieveTransformQueryConfig QueryConfig.retrieveTransformQueryConfig
@@ -50,10 +50,3 @@ export const AdminUpdateSalesChannel = z.object({
is_disabled: z.boolean().optional(), is_disabled: z.boolean().optional(),
metadata: z.record(z.string(), z.unknown()).optional(), metadata: z.record(z.string(), z.unknown()).optional(),
}) })
export type AdminSetSalesChannelProductsBatchType = z.infer<
typeof AdminSetSalesChannelProductsBatch
>
export const AdminSetSalesChannelProductsBatch = z.object({
product_ids: z.array(z.string()),
})
@@ -1,37 +0,0 @@
import {
MedusaRequest,
MedusaResponse,
} from "../../../../../../../types/routing"
import { AdminStockLocationsSalesChannelType } from "../../../../validators"
import { addLocationsToSalesChannelWorkflow } from "@medusajs/core-flows"
import { refetchStockLocation } from "../../../../helpers"
export const POST = async (
req: MedusaRequest<AdminStockLocationsSalesChannelType>,
res: MedusaResponse
) => {
const workflowInput = {
data: req.validatedBody.sales_channel_ids.map((id) => ({
sales_channel_id: id,
location_ids: [req.params.id],
})),
}
const { errors } = await addLocationsToSalesChannelWorkflow(req.scope).run({
input: workflowInput,
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const stockLocation = await refetchStockLocation(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ stock_location: stockLocation })
}
@@ -1,39 +0,0 @@
import {
MedusaRequest,
MedusaResponse,
} from "../../../../../../../types/routing"
import { AdminStockLocationsSalesChannelType } from "../../../../validators"
import { removeLocationsFromSalesChannelWorkflow } from "@medusajs/core-flows"
import { refetchStockLocation } from "../../../../helpers"
export const POST = async (
req: MedusaRequest<AdminStockLocationsSalesChannelType>,
res: MedusaResponse
) => {
const workflowInput = {
data: req.validatedBody.sales_channel_ids.map((id) => ({
sales_channel_id: id,
location_ids: [req.params.id],
})),
}
const { errors } = await removeLocationsFromSalesChannelWorkflow(
req.scope
).run({
input: workflowInput,
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const stockLocation = await refetchStockLocation(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ stock_location: stockLocation })
}
@@ -0,0 +1,37 @@
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../../types/routing"
import { LinkMethodRequest } from "@medusajs/types/src"
import { refetchStockLocation } from "../../helpers"
import { linkSalesChannelsToStockLocationWorkflow } from "@medusajs/core-flows"
export const POST = async (
req: AuthenticatedMedusaRequest<LinkMethodRequest>,
res: MedusaResponse
) => {
const { id } = req.params
const { add, remove } = req.validatedBody
const workflow = linkSalesChannelsToStockLocationWorkflow(req.scope)
const { errors } = await workflow.run({
input: {
id,
add,
remove,
},
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const stockLocation = await refetchStockLocation(
req.params.id,
req.scope,
req.remoteQueryConfig.fields
)
res.status(200).json({ stock_location: stockLocation })
}
@@ -3,13 +3,13 @@ import { authenticate } from "../../../utils/authenticate-middleware"
import { maybeApplyLinkFilter } from "../../utils/maybe-apply-link-filter" import { maybeApplyLinkFilter } from "../../utils/maybe-apply-link-filter"
import { validateAndTransformBody } from "../../utils/validate-body" import { validateAndTransformBody } from "../../utils/validate-body"
import { validateAndTransformQuery } from "../../utils/validate-query" import { validateAndTransformQuery } from "../../utils/validate-query"
import { createLinkBody } from "../../utils/validators"
import * as QueryConfig from "./query-config" import * as QueryConfig from "./query-config"
import { import {
AdminCreateStockLocation, AdminCreateStockLocation,
AdminCreateStockLocationFulfillmentSet, AdminCreateStockLocationFulfillmentSet,
AdminGetStockLocationParams, AdminGetStockLocationParams,
AdminGetStockLocationsParams, AdminGetStockLocationsParams,
AdminStockLocationsSalesChannel,
AdminUpdateStockLocation, AdminUpdateStockLocation,
} from "./validators" } from "./validators"
@@ -79,9 +79,9 @@ export const adminStockLocationRoutesMiddlewares: MiddlewareRoute[] = [
}, },
{ {
method: ["POST"], method: ["POST"],
matcher: "/admin/stock-locations/:id/sales-channels/batch*", matcher: "/admin/stock-locations/:id/sales-channels",
middlewares: [ middlewares: [
validateAndTransformBody(AdminStockLocationsSalesChannel), validateAndTransformBody(createLinkBody()),
validateAndTransformQuery( validateAndTransformQuery(
AdminGetStockLocationParams, AdminGetStockLocationParams,
QueryConfig.retrieveTransformQueryConfig QueryConfig.retrieveTransformQueryConfig
@@ -60,13 +60,6 @@ export const AdminUpdateStockLocation = z.object({
metadata: z.record(z.unknown()).optional(), metadata: z.record(z.unknown()).optional(),
}) })
export type AdminStockLocationsSalesChannelType = z.infer<
typeof AdminStockLocationsSalesChannel
>
export const AdminStockLocationsSalesChannel = z.object({
sales_channel_ids: z.array(z.string()),
})
export type AdminCreateStockLocationFulfillmentSetType = z.infer< export type AdminCreateStockLocationFulfillmentSetType = z.infer<
typeof AdminCreateStockLocationFulfillmentSet typeof AdminCreateStockLocationFulfillmentSet
> >
+15 -2
View File
@@ -3,13 +3,19 @@ export type LinkMethodRequest = {
remove?: string[] remove?: string[]
} }
export type BatchMethodRequest<TCreate extends any, TUpdate extends any> = { export type LinkWorkflowInput = {
id: string
add?: string[]
remove?: string[]
}
export type BatchMethodRequest<TCreate, TUpdate> = {
create?: TCreate[] create?: TCreate[]
update?: TUpdate[] update?: TUpdate[]
delete?: string[] delete?: string[]
} }
export type BatchMethodResponse<T extends any> = { export type BatchMethodResponse<T> = {
created: T[] created: T[]
updated: T[] updated: T[]
deleted: { deleted: {
@@ -18,3 +24,10 @@ export type BatchMethodResponse<T extends any> = {
deleted: boolean deleted: boolean
} }
} }
export type BatchWorkflowInput<TCreate, TUpdate> = BatchMethodRequest<
TCreate,
TUpdate
>
export type BatchWorkflowOutput<T> = BatchMethodResponse<T>
@@ -1,5 +1,23 @@
import { LinkMethodRequest } from "../../common" import { PricingTypes, ProductTypes } from "../../bundles"
export interface BatchLinkProductsToCollectionDTO extends LinkMethodRequest { export type CreateProductVariantWorkflowInputDTO =
id: string ProductTypes.CreateProductVariantDTO & {
prices?: PricingTypes.CreateMoneyAmountDTO[]
}
export type UpdateProductVariantWorkflowInputDTO =
(ProductTypes.UpsertProductVariantDTO & {
prices?: PricingTypes.CreateMoneyAmountDTO[]
})[]
export type CreateProductWorkflowInputDTO = Omit<
ProductTypes.CreateProductDTO,
"variants"
> & {
sales_channels?: { id: string }[]
variants?: CreateProductVariantWorkflowInputDTO[]
}
export type UpdateProductWorkflowInputDTO = ProductTypes.UpsertProductDTO & {
sales_channels?: { id: string }[]
} }