feature: add hooks to campaigns (#8450)

This commit is contained in:
Harminder Virk
2024-08-06 15:15:41 +05:30
committed by GitHub
parent f415e6664c
commit 8fb079786d
12 changed files with 164 additions and 61 deletions
@@ -1,17 +1,26 @@
import { CampaignDTO, CreateCampaignDTO } from "@medusajs/types" import { AdditionalData, CreateCampaignDTO } from "@medusajs/types"
import { import {
WorkflowData, WorkflowData,
WorkflowResponse, WorkflowResponse,
createHook,
createWorkflow, createWorkflow,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { createCampaignsStep } from "../steps" import { createCampaignsStep } from "../steps"
type WorkflowInput = { campaignsData: CreateCampaignDTO[] } type WorkflowInput = { campaignsData: CreateCampaignDTO[] } & AdditionalData
export const createCampaignsWorkflowId = "create-campaigns" export const createCampaignsWorkflowId = "create-campaigns"
export const createCampaignsWorkflow = createWorkflow( export const createCampaignsWorkflow = createWorkflow(
createCampaignsWorkflowId, createCampaignsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowResponse<CampaignDTO[]> => { (input: WorkflowData<WorkflowInput>) => {
return new WorkflowResponse(createCampaignsStep(input.campaignsData)) const createdCampaigns = createCampaignsStep(input.campaignsData)
const campaignsCreated = createHook("campaignsCreated", {
campaigns: createdCampaigns,
additional_data: input.additional_data,
})
return new WorkflowResponse(createdCampaigns, {
hooks: [campaignsCreated],
})
} }
) )
@@ -1,17 +1,26 @@
import { CreatePromotionDTO, PromotionDTO } from "@medusajs/types" import { AdditionalData, CreatePromotionDTO } from "@medusajs/types"
import { import {
WorkflowData, WorkflowData,
WorkflowResponse, WorkflowResponse,
createHook,
createWorkflow, createWorkflow,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { createPromotionsStep } from "../steps" import { createPromotionsStep } from "../steps"
type WorkflowInput = { promotionsData: CreatePromotionDTO[] } type WorkflowInput = { promotionsData: CreatePromotionDTO[] } & AdditionalData
export const createPromotionsWorkflowId = "create-promotions" export const createPromotionsWorkflowId = "create-promotions"
export const createPromotionsWorkflow = createWorkflow( export const createPromotionsWorkflow = createWorkflow(
createPromotionsWorkflowId, createPromotionsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowResponse<PromotionDTO[]> => { (input: WorkflowData<WorkflowInput>) => {
return new WorkflowResponse(createPromotionsStep(input.promotionsData)) const createdPromotions = createPromotionsStep(input.promotionsData)
const promotionsCreated = createHook("promotionsCreated", {
promotions: createdPromotions,
additional_data: input.additional_data,
})
return new WorkflowResponse(createdPromotions, {
hooks: [promotionsCreated],
})
} }
) )
@@ -1,4 +1,4 @@
import { createWorkflow, WorkflowData } from "@medusajs/workflows-sdk" import { createHook, createWorkflow, WorkflowData, WorkflowResponse } from "@medusajs/workflows-sdk"
import { deleteCampaignsStep } from "../steps" import { deleteCampaignsStep } from "../steps"
type WorkflowInput = { ids: string[] } type WorkflowInput = { ids: string[] }
@@ -6,7 +6,14 @@ type WorkflowInput = { ids: string[] }
export const deleteCampaignsWorkflowId = "delete-campaigns" export const deleteCampaignsWorkflowId = "delete-campaigns"
export const deleteCampaignsWorkflow = createWorkflow( export const deleteCampaignsWorkflow = createWorkflow(
deleteCampaignsWorkflowId, deleteCampaignsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => { (input: WorkflowData<WorkflowInput>) => {
return deleteCampaignsStep(input.ids) const deletedCampaigns = deleteCampaignsStep(input.ids)
const campaignsDeleted = createHook("campaignsDeleted", {
ids: input.ids
})
return new WorkflowResponse(deletedCampaigns, {
hooks: [campaignsDeleted]
})
} }
) )
@@ -1,4 +1,4 @@
import { createWorkflow, WorkflowData } from "@medusajs/workflows-sdk" import { createHook, createWorkflow, WorkflowData, WorkflowResponse } from "@medusajs/workflows-sdk"
import { deletePromotionsStep } from "../steps" import { deletePromotionsStep } from "../steps"
type WorkflowInput = { ids: string[] } type WorkflowInput = { ids: string[] }
@@ -6,7 +6,14 @@ type WorkflowInput = { ids: string[] }
export const deletePromotionsWorkflowId = "delete-promotions" export const deletePromotionsWorkflowId = "delete-promotions"
export const deletePromotionsWorkflow = createWorkflow( export const deletePromotionsWorkflow = createWorkflow(
deletePromotionsWorkflowId, deletePromotionsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => { (input: WorkflowData<WorkflowInput>) => {
return deletePromotionsStep(input.ids) const deletedPromotions = deletePromotionsStep(input.ids)
const promotionsDeleted = createHook("promotionsDeleted", {
ids: input.ids
})
return new WorkflowResponse(deletedPromotions, {
hooks: [promotionsDeleted]
})
} }
) )
@@ -1,17 +1,26 @@
import { CampaignDTO, UpdateCampaignDTO } from "@medusajs/types" import { AdditionalData, UpdateCampaignDTO } from "@medusajs/types"
import { import {
WorkflowData, WorkflowData,
WorkflowResponse, WorkflowResponse,
createHook,
createWorkflow, createWorkflow,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { updateCampaignsStep } from "../steps" import { updateCampaignsStep } from "../steps"
type WorkflowInput = { campaignsData: UpdateCampaignDTO[] } type WorkflowInput = { campaignsData: UpdateCampaignDTO[] } & AdditionalData
export const updateCampaignsWorkflowId = "update-campaigns" export const updateCampaignsWorkflowId = "update-campaigns"
export const updateCampaignsWorkflow = createWorkflow( export const updateCampaignsWorkflow = createWorkflow(
updateCampaignsWorkflowId, updateCampaignsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowResponse<CampaignDTO[]> => { (input: WorkflowData<WorkflowInput>) => {
return new WorkflowResponse(updateCampaignsStep(input.campaignsData)) const updatedCampaigns = updateCampaignsStep(input.campaignsData)
const campaignsUpdated = createHook("campaignsUpdated", {
campaigns: updatedCampaigns,
additional_data: input.additional_data,
})
return new WorkflowResponse(updatedCampaigns, {
hooks: [campaignsUpdated],
})
} }
) )
@@ -1,17 +1,29 @@
import { PromotionDTO, UpdatePromotionDTO } from "@medusajs/types" import {
AdditionalData,
UpdatePromotionDTO,
} from "@medusajs/types"
import { import {
WorkflowData, WorkflowData,
WorkflowResponse, WorkflowResponse,
createHook,
createWorkflow, createWorkflow,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { updatePromotionsStep } from "../steps" import { updatePromotionsStep } from "../steps"
type WorkflowInput = { promotionsData: UpdatePromotionDTO[] } type WorkflowInput = { promotionsData: UpdatePromotionDTO[] } & AdditionalData
export const updatePromotionsWorkflowId = "update-promotions" export const updatePromotionsWorkflowId = "update-promotions"
export const updatePromotionsWorkflow = createWorkflow( export const updatePromotionsWorkflow = createWorkflow(
updatePromotionsWorkflowId, updatePromotionsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowResponse<PromotionDTO[]> => { (input: WorkflowData<WorkflowInput>) => {
return new WorkflowResponse(updatePromotionsStep(input.promotionsData)) const updatedPromotions = updatePromotionsStep(input.promotionsData)
const promotionsUpdated = createHook("promotionsUpdated", {
promotions: updatedPromotions,
additional_data: input.additional_data,
})
return new WorkflowResponse(updatedPromotions, {
hooks: [promotionsUpdated],
})
} }
) )
@@ -10,6 +10,7 @@ import {
import { refetchCampaign } from "../helpers" import { refetchCampaign } from "../helpers"
import { AdminUpdateCampaignType } from "../validators" import { AdminUpdateCampaignType } from "../validators"
import { MedusaError } from "@medusajs/utils" import { MedusaError } from "@medusajs/utils"
import { AdditionalData } from "@medusajs/types"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
@@ -32,19 +33,20 @@ export const GET = async (
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminUpdateCampaignType>, req: AuthenticatedMedusaRequest<AdminUpdateCampaignType & AdditionalData>,
res: MedusaResponse res: MedusaResponse
) => { ) => {
const { additional_data, ...rest } = req.validatedBody
const updateCampaigns = updateCampaignsWorkflow(req.scope) const updateCampaigns = updateCampaignsWorkflow(req.scope)
const campaignsData = [ const campaignsData = [
{ {
id: req.params.id, id: req.params.id,
...req.validatedBody, ...rest,
}, },
] ]
await updateCampaigns.run({ await updateCampaigns.run({
input: { campaignsData }, input: { campaignsData, additional_data },
}) })
const campaign = await refetchCampaign( const campaign = await refetchCampaign(
@@ -2,13 +2,14 @@ import {
AuthenticatedMedusaRequest, AuthenticatedMedusaRequest,
MedusaResponse, MedusaResponse,
} from "../../../types/routing" } from "../../../types/routing"
import {createCampaignsWorkflow} from "@medusajs/core-flows" import { createCampaignsWorkflow } from "@medusajs/core-flows"
import { import {
ContainerRegistrationKeys, ContainerRegistrationKeys,
remoteQueryObjectFromString, remoteQueryObjectFromString,
} from "@medusajs/utils" } from "@medusajs/utils"
import {AdminCreateCampaignType} from "./validators" import { AdminCreateCampaignType } from "./validators"
import {refetchCampaign} from "./helpers" import { refetchCampaign } from "./helpers"
import { AdditionalData } from "@medusajs/types"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
@@ -36,14 +37,15 @@ export const GET = async (
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminCreateCampaignType>, req: AuthenticatedMedusaRequest<AdminCreateCampaignType & AdditionalData>,
res: MedusaResponse res: MedusaResponse
) => { ) => {
const { additional_data, ...rest } = req.validatedBody
const createCampaigns = createCampaignsWorkflow(req.scope) const createCampaigns = createCampaignsWorkflow(req.scope)
const campaignsData = [req.validatedBody] const campaignsData = [rest]
const { result } = await createCampaigns.run({ const { result } = await createCampaigns.run({
input: { campaignsData }, input: { campaignsData, additional_data },
context: { context: {
requestId: req.requestId, requestId: req.requestId,
}, },
@@ -1,5 +1,5 @@
import { CampaignBudgetType, isPresent } from "@medusajs/utils" import { CampaignBudgetType, isPresent } from "@medusajs/utils"
import { z } from "zod" import { z, ZodObject } from "zod"
import { createFindParams, createSelectParams } from "../../utils/validators" import { createFindParams, createSelectParams } from "../../utils/validators"
export const AdminGetCampaignParams = createSelectParams() export const AdminGetCampaignParams = createSelectParams()
@@ -56,8 +56,8 @@ export const UpdateCampaignBudget = z
}) })
.strict() .strict()
export type AdminCreateCampaignType = z.infer<typeof AdminCreateCampaign> export type AdminCreateCampaignType = z.infer<typeof CreateCampaign>
export const AdminCreateCampaign = z export const CreateCampaign = z
.object({ .object({
name: z.string(), name: z.string(),
campaign_identifier: z.string(), campaign_identifier: z.string(),
@@ -68,9 +68,22 @@ export const AdminCreateCampaign = z
promotions: z.array(z.object({ id: z.string() })).optional(), promotions: z.array(z.object({ id: z.string() })).optional(),
}) })
.strict() .strict()
export const AdminCreateCampaign = (
additionalDataValidator?: ZodObject<any, any>
) => {
if (!additionalDataValidator) {
return CreateCampaign.extend({
additional_data: z.record(z.unknown()).nullish(),
})
}
export type AdminUpdateCampaignType = z.infer<typeof AdminUpdateCampaign> return CreateCampaign.extend({
export const AdminUpdateCampaign = z.object({ additional_data: additionalDataValidator,
})
}
export type AdminUpdateCampaignType = z.infer<typeof UpdateCampaign>
export const UpdateCampaign = z.object({
name: z.string().optional(), name: z.string().optional(),
campaign_identifier: z.string().optional(), campaign_identifier: z.string().optional(),
description: z.string().nullish(), description: z.string().nullish(),
@@ -79,3 +92,16 @@ export const AdminUpdateCampaign = z.object({
ends_at: z.coerce.date().nullish(), ends_at: z.coerce.date().nullish(),
promotions: z.array(z.object({ id: z.string() })).optional(), promotions: z.array(z.object({ id: z.string() })).optional(),
}) })
export const AdminUpdateCampaign = (
additionalDataValidator?: ZodObject<any, any>
) => {
if (!additionalDataValidator) {
return UpdateCampaign.extend({
additional_data: z.record(z.unknown()).nullish(),
})
}
return UpdateCampaign.extend({
additional_data: additionalDataValidator,
})
}
@@ -16,6 +16,7 @@ import {
AdminGetPromotionParamsType, AdminGetPromotionParamsType,
AdminUpdatePromotionType, AdminUpdatePromotionType,
} from "../validators" } from "../validators"
import { AdditionalData } from "@medusajs/types"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest<AdminGetPromotionParamsType>, req: AuthenticatedMedusaRequest<AdminGetPromotionParamsType>,
@@ -43,19 +44,20 @@ export const GET = async (
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminUpdatePromotionType>, req: AuthenticatedMedusaRequest<AdminUpdatePromotionType & AdditionalData>,
res: MedusaResponse res: MedusaResponse
) => { ) => {
const { additional_data, ...rest } = req.validatedBody
const updatePromotions = updatePromotionsWorkflow(req.scope) const updatePromotions = updatePromotionsWorkflow(req.scope)
const promotionsData = [ const promotionsData = [
{ {
id: req.params.id, id: req.params.id,
...req.validatedBody, ...rest,
} as any, } as any,
] ]
await updatePromotions.run({ await updatePromotions.run({
input: { promotionsData }, input: { promotionsData, additional_data },
}) })
const promotion = await refetchPromotion( const promotion = await refetchPromotion(
@@ -12,6 +12,7 @@ import {
AdminCreatePromotionType, AdminCreatePromotionType,
AdminGetPromotionsParamsType, AdminGetPromotionsParamsType,
} from "./validators" } from "./validators"
import { AdditionalData } from "@medusajs/types"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest<AdminGetPromotionsParamsType>, req: AuthenticatedMedusaRequest<AdminGetPromotionsParamsType>,
@@ -39,14 +40,15 @@ export const GET = async (
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminCreatePromotionType>, req: AuthenticatedMedusaRequest<AdminCreatePromotionType & AdditionalData>,
res: MedusaResponse res: MedusaResponse
) => { ) => {
const { additional_data, ...rest } = req.validatedBody
const createPromotions = createPromotionsWorkflow(req.scope) const createPromotions = createPromotionsWorkflow(req.scope)
const promotionsData = [req.validatedBody] as any const promotionsData = [rest] as any
const { result } = await createPromotions.run({ const { result } = await createPromotions.run({
input: { promotionsData }, input: { promotionsData, additional_data },
}) })
const promotion = await refetchPromotion( const promotion = await refetchPromotion(
@@ -11,7 +11,7 @@ import {
createOperatorMap, createOperatorMap,
createSelectParams, createSelectParams,
} from "../../utils/validators" } from "../../utils/validators"
import { AdminCreateCampaign } from "../campaigns/validators" import { CreateCampaign } from "../campaigns/validators"
export type AdminGetPromotionParamsType = z.infer< export type AdminGetPromotionParamsType = z.infer<
typeof AdminGetPromotionParams typeof AdminGetPromotionParams
@@ -155,51 +155,67 @@ const promoRefinement = (promo) => {
return true return true
} }
export type AdminCreatePromotionType = z.infer<typeof _AdminCreatePromotion> export type AdminCreatePromotionType = z.infer<typeof CreatePromotion>
const _AdminCreatePromotion = z export const CreatePromotion = z
.object({ .object({
code: z.string(), code: z.string(),
is_automatic: z.boolean().optional(), is_automatic: z.boolean().optional(),
type: z.nativeEnum(PromotionType), type: z.nativeEnum(PromotionType),
campaign_id: z.string().nullish(), campaign_id: z.string().nullish(),
campaign: AdminCreateCampaign.optional(), campaign: CreateCampaign.optional(),
application_method: AdminCreateApplicationMethod, application_method: AdminCreateApplicationMethod,
rules: z.array(AdminCreatePromotionRule).optional(), rules: z.array(AdminCreatePromotionRule).optional(),
}) })
.strict() .strict()
export const AdminCreatePromotion = (customSchema?: ZodObject<any, any>) => { export const AdminCreatePromotion = (
const schema = customSchema additionalDataValidator?: ZodObject<any, any>
? _AdminCreatePromotion.merge(customSchema) ) => {
: _AdminCreatePromotion if (!additionalDataValidator) {
return CreatePromotion.extend({
additional_data: z.record(z.unknown()).nullish(),
}).refine(promoRefinement, {
message:
"Buyget promotions require at least one buy rule and quantities to be defined",
})
}
// In the case of a buyget promotion, we require at least one buy rule and quantities return CreatePromotion.extend({
return schema.refine(promoRefinement, { additional_data: additionalDataValidator,
}).refine(promoRefinement, {
message: message:
"Buyget promotions require at least one buy rule and quantities to be defined", "Buyget promotions require at least one buy rule and quantities to be defined",
}) })
} }
export type AdminUpdatePromotionType = z.infer<typeof _AdminUpdatePromotion> export type AdminUpdatePromotionType = z.infer<typeof UpdatePromotion>
const _AdminUpdatePromotion = z export const UpdatePromotion = z
.object({ .object({
code: z.string().optional(), code: z.string().optional(),
is_automatic: z.boolean().optional(), is_automatic: z.boolean().optional(),
type: z.nativeEnum(PromotionType).optional(), type: z.nativeEnum(PromotionType).optional(),
campaign_id: z.string().nullish(), campaign_id: z.string().nullish(),
campaign: AdminCreateCampaign.optional(), campaign: CreateCampaign.optional(),
application_method: AdminUpdateApplicationMethod.optional(), application_method: AdminUpdateApplicationMethod.optional(),
rules: z.array(AdminCreatePromotionRule).optional(), rules: z.array(AdminCreatePromotionRule).optional(),
}) })
.strict() .strict()
export const AdminUpdatePromotion = (customSchema?: ZodObject<any, any>) => { export const AdminUpdatePromotion = (
const schema = customSchema additionalDataValidator?: ZodObject<any, any>
? _AdminUpdatePromotion.merge(customSchema) ) => {
: _AdminUpdatePromotion if (!additionalDataValidator) {
return UpdatePromotion.extend({
additional_data: z.record(z.unknown()).nullish(),
}).refine(promoRefinement, {
message:
"Buyget promotions require at least one buy rule and quantities to be defined",
})
}
// In the case of a buyget promotion, we require at least one buy rule and quantities return UpdatePromotion.extend({
return schema.refine(promoRefinement, { additional_data: additionalDataValidator,
}).refine(promoRefinement, {
message: message:
"Buyget promotions require at least one buy rule and quantities to be defined", "Buyget promotions require at least one buy rule and quantities to be defined",
}) })