diff --git a/packages/core/core-flows/src/promotion/workflows/create-campaigns.ts b/packages/core/core-flows/src/promotion/workflows/create-campaigns.ts index bfcc5e5c8b..38096f2a96 100644 --- a/packages/core/core-flows/src/promotion/workflows/create-campaigns.ts +++ b/packages/core/core-flows/src/promotion/workflows/create-campaigns.ts @@ -1,17 +1,26 @@ -import { CampaignDTO, CreateCampaignDTO } from "@medusajs/types" +import { AdditionalData, CreateCampaignDTO } from "@medusajs/types" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, } from "@medusajs/workflows-sdk" import { createCampaignsStep } from "../steps" -type WorkflowInput = { campaignsData: CreateCampaignDTO[] } +type WorkflowInput = { campaignsData: CreateCampaignDTO[] } & AdditionalData export const createCampaignsWorkflowId = "create-campaigns" export const createCampaignsWorkflow = createWorkflow( createCampaignsWorkflowId, - (input: WorkflowData): WorkflowResponse => { - return new WorkflowResponse(createCampaignsStep(input.campaignsData)) + (input: WorkflowData) => { + const createdCampaigns = createCampaignsStep(input.campaignsData) + const campaignsCreated = createHook("campaignsCreated", { + campaigns: createdCampaigns, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(createdCampaigns, { + hooks: [campaignsCreated], + }) } ) diff --git a/packages/core/core-flows/src/promotion/workflows/create-promotions.ts b/packages/core/core-flows/src/promotion/workflows/create-promotions.ts index 240b5d01b6..0ce51df955 100644 --- a/packages/core/core-flows/src/promotion/workflows/create-promotions.ts +++ b/packages/core/core-flows/src/promotion/workflows/create-promotions.ts @@ -1,17 +1,26 @@ -import { CreatePromotionDTO, PromotionDTO } from "@medusajs/types" +import { AdditionalData, CreatePromotionDTO } from "@medusajs/types" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, } from "@medusajs/workflows-sdk" import { createPromotionsStep } from "../steps" -type WorkflowInput = { promotionsData: CreatePromotionDTO[] } +type WorkflowInput = { promotionsData: CreatePromotionDTO[] } & AdditionalData export const createPromotionsWorkflowId = "create-promotions" export const createPromotionsWorkflow = createWorkflow( createPromotionsWorkflowId, - (input: WorkflowData): WorkflowResponse => { - return new WorkflowResponse(createPromotionsStep(input.promotionsData)) + (input: WorkflowData) => { + const createdPromotions = createPromotionsStep(input.promotionsData) + const promotionsCreated = createHook("promotionsCreated", { + promotions: createdPromotions, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(createdPromotions, { + hooks: [promotionsCreated], + }) } ) diff --git a/packages/core/core-flows/src/promotion/workflows/delete-campaigns.ts b/packages/core/core-flows/src/promotion/workflows/delete-campaigns.ts index a6c14f4e04..2d4707d677 100644 --- a/packages/core/core-flows/src/promotion/workflows/delete-campaigns.ts +++ b/packages/core/core-flows/src/promotion/workflows/delete-campaigns.ts @@ -1,4 +1,4 @@ -import { createWorkflow, WorkflowData } from "@medusajs/workflows-sdk" +import { createHook, createWorkflow, WorkflowData, WorkflowResponse } from "@medusajs/workflows-sdk" import { deleteCampaignsStep } from "../steps" type WorkflowInput = { ids: string[] } @@ -6,7 +6,14 @@ type WorkflowInput = { ids: string[] } export const deleteCampaignsWorkflowId = "delete-campaigns" export const deleteCampaignsWorkflow = createWorkflow( deleteCampaignsWorkflowId, - (input: WorkflowData): WorkflowData => { - return deleteCampaignsStep(input.ids) + (input: WorkflowData) => { + const deletedCampaigns = deleteCampaignsStep(input.ids) + const campaignsDeleted = createHook("campaignsDeleted", { + ids: input.ids + }) + + return new WorkflowResponse(deletedCampaigns, { + hooks: [campaignsDeleted] + }) } ) diff --git a/packages/core/core-flows/src/promotion/workflows/delete-promotions.ts b/packages/core/core-flows/src/promotion/workflows/delete-promotions.ts index 7223afaa8a..8a741d1acc 100644 --- a/packages/core/core-flows/src/promotion/workflows/delete-promotions.ts +++ b/packages/core/core-flows/src/promotion/workflows/delete-promotions.ts @@ -1,4 +1,4 @@ -import { createWorkflow, WorkflowData } from "@medusajs/workflows-sdk" +import { createHook, createWorkflow, WorkflowData, WorkflowResponse } from "@medusajs/workflows-sdk" import { deletePromotionsStep } from "../steps" type WorkflowInput = { ids: string[] } @@ -6,7 +6,14 @@ type WorkflowInput = { ids: string[] } export const deletePromotionsWorkflowId = "delete-promotions" export const deletePromotionsWorkflow = createWorkflow( deletePromotionsWorkflowId, - (input: WorkflowData): WorkflowData => { - return deletePromotionsStep(input.ids) + (input: WorkflowData) => { + const deletedPromotions = deletePromotionsStep(input.ids) + const promotionsDeleted = createHook("promotionsDeleted", { + ids: input.ids + }) + + return new WorkflowResponse(deletedPromotions, { + hooks: [promotionsDeleted] + }) } ) diff --git a/packages/core/core-flows/src/promotion/workflows/update-campaigns.ts b/packages/core/core-flows/src/promotion/workflows/update-campaigns.ts index 7566b6da29..af23b93acb 100644 --- a/packages/core/core-flows/src/promotion/workflows/update-campaigns.ts +++ b/packages/core/core-flows/src/promotion/workflows/update-campaigns.ts @@ -1,17 +1,26 @@ -import { CampaignDTO, UpdateCampaignDTO } from "@medusajs/types" +import { AdditionalData, UpdateCampaignDTO } from "@medusajs/types" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, } from "@medusajs/workflows-sdk" import { updateCampaignsStep } from "../steps" -type WorkflowInput = { campaignsData: UpdateCampaignDTO[] } +type WorkflowInput = { campaignsData: UpdateCampaignDTO[] } & AdditionalData export const updateCampaignsWorkflowId = "update-campaigns" export const updateCampaignsWorkflow = createWorkflow( updateCampaignsWorkflowId, - (input: WorkflowData): WorkflowResponse => { - return new WorkflowResponse(updateCampaignsStep(input.campaignsData)) + (input: WorkflowData) => { + const updatedCampaigns = updateCampaignsStep(input.campaignsData) + const campaignsUpdated = createHook("campaignsUpdated", { + campaigns: updatedCampaigns, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(updatedCampaigns, { + hooks: [campaignsUpdated], + }) } ) diff --git a/packages/core/core-flows/src/promotion/workflows/update-promotions.ts b/packages/core/core-flows/src/promotion/workflows/update-promotions.ts index 559b1ea957..43ff820818 100644 --- a/packages/core/core-flows/src/promotion/workflows/update-promotions.ts +++ b/packages/core/core-flows/src/promotion/workflows/update-promotions.ts @@ -1,17 +1,29 @@ -import { PromotionDTO, UpdatePromotionDTO } from "@medusajs/types" +import { + AdditionalData, + UpdatePromotionDTO, +} from "@medusajs/types" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, } from "@medusajs/workflows-sdk" import { updatePromotionsStep } from "../steps" -type WorkflowInput = { promotionsData: UpdatePromotionDTO[] } +type WorkflowInput = { promotionsData: UpdatePromotionDTO[] } & AdditionalData export const updatePromotionsWorkflowId = "update-promotions" export const updatePromotionsWorkflow = createWorkflow( updatePromotionsWorkflowId, - (input: WorkflowData): WorkflowResponse => { - return new WorkflowResponse(updatePromotionsStep(input.promotionsData)) + (input: WorkflowData) => { + const updatedPromotions = updatePromotionsStep(input.promotionsData) + const promotionsUpdated = createHook("promotionsUpdated", { + promotions: updatedPromotions, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(updatedPromotions, { + hooks: [promotionsUpdated], + }) } ) diff --git a/packages/medusa/src/api/admin/campaigns/[id]/route.ts b/packages/medusa/src/api/admin/campaigns/[id]/route.ts index ae4b5bd75b..7347ed7bca 100644 --- a/packages/medusa/src/api/admin/campaigns/[id]/route.ts +++ b/packages/medusa/src/api/admin/campaigns/[id]/route.ts @@ -10,6 +10,7 @@ import { import { refetchCampaign } from "../helpers" import { AdminUpdateCampaignType } from "../validators" import { MedusaError } from "@medusajs/utils" +import { AdditionalData } from "@medusajs/types" export const GET = async ( req: AuthenticatedMedusaRequest, @@ -32,19 +33,20 @@ export const GET = async ( } export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { + const { additional_data, ...rest } = req.validatedBody const updateCampaigns = updateCampaignsWorkflow(req.scope) const campaignsData = [ { id: req.params.id, - ...req.validatedBody, + ...rest, }, ] await updateCampaigns.run({ - input: { campaignsData }, + input: { campaignsData, additional_data }, }) const campaign = await refetchCampaign( diff --git a/packages/medusa/src/api/admin/campaigns/route.ts b/packages/medusa/src/api/admin/campaigns/route.ts index 988b7dacba..f98d1369a7 100644 --- a/packages/medusa/src/api/admin/campaigns/route.ts +++ b/packages/medusa/src/api/admin/campaigns/route.ts @@ -2,13 +2,14 @@ import { AuthenticatedMedusaRequest, MedusaResponse, } from "../../../types/routing" -import {createCampaignsWorkflow} from "@medusajs/core-flows" +import { createCampaignsWorkflow } from "@medusajs/core-flows" import { ContainerRegistrationKeys, remoteQueryObjectFromString, } from "@medusajs/utils" -import {AdminCreateCampaignType} from "./validators" -import {refetchCampaign} from "./helpers" +import { AdminCreateCampaignType } from "./validators" +import { refetchCampaign } from "./helpers" +import { AdditionalData } from "@medusajs/types" export const GET = async ( req: AuthenticatedMedusaRequest, @@ -36,14 +37,15 @@ export const GET = async ( } export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { + const { additional_data, ...rest } = req.validatedBody const createCampaigns = createCampaignsWorkflow(req.scope) - const campaignsData = [req.validatedBody] + const campaignsData = [rest] const { result } = await createCampaigns.run({ - input: { campaignsData }, + input: { campaignsData, additional_data }, context: { requestId: req.requestId, }, diff --git a/packages/medusa/src/api/admin/campaigns/validators.ts b/packages/medusa/src/api/admin/campaigns/validators.ts index ddd0b03612..0dd4a7d160 100644 --- a/packages/medusa/src/api/admin/campaigns/validators.ts +++ b/packages/medusa/src/api/admin/campaigns/validators.ts @@ -1,5 +1,5 @@ import { CampaignBudgetType, isPresent } from "@medusajs/utils" -import { z } from "zod" +import { z, ZodObject } from "zod" import { createFindParams, createSelectParams } from "../../utils/validators" export const AdminGetCampaignParams = createSelectParams() @@ -56,8 +56,8 @@ export const UpdateCampaignBudget = z }) .strict() -export type AdminCreateCampaignType = z.infer -export const AdminCreateCampaign = z +export type AdminCreateCampaignType = z.infer +export const CreateCampaign = z .object({ name: z.string(), campaign_identifier: z.string(), @@ -68,9 +68,22 @@ export const AdminCreateCampaign = z promotions: z.array(z.object({ id: z.string() })).optional(), }) .strict() +export const AdminCreateCampaign = ( + additionalDataValidator?: ZodObject +) => { + if (!additionalDataValidator) { + return CreateCampaign.extend({ + additional_data: z.record(z.unknown()).nullish(), + }) + } -export type AdminUpdateCampaignType = z.infer -export const AdminUpdateCampaign = z.object({ + return CreateCampaign.extend({ + additional_data: additionalDataValidator, + }) +} + +export type AdminUpdateCampaignType = z.infer +export const UpdateCampaign = z.object({ name: z.string().optional(), campaign_identifier: z.string().optional(), description: z.string().nullish(), @@ -79,3 +92,16 @@ export const AdminUpdateCampaign = z.object({ ends_at: z.coerce.date().nullish(), promotions: z.array(z.object({ id: z.string() })).optional(), }) +export const AdminUpdateCampaign = ( + additionalDataValidator?: ZodObject +) => { + if (!additionalDataValidator) { + return UpdateCampaign.extend({ + additional_data: z.record(z.unknown()).nullish(), + }) + } + + return UpdateCampaign.extend({ + additional_data: additionalDataValidator, + }) +} diff --git a/packages/medusa/src/api/admin/promotions/[id]/route.ts b/packages/medusa/src/api/admin/promotions/[id]/route.ts index 12badbee95..b3c8c0593b 100644 --- a/packages/medusa/src/api/admin/promotions/[id]/route.ts +++ b/packages/medusa/src/api/admin/promotions/[id]/route.ts @@ -16,6 +16,7 @@ import { AdminGetPromotionParamsType, AdminUpdatePromotionType, } from "../validators" +import { AdditionalData } from "@medusajs/types" export const GET = async ( req: AuthenticatedMedusaRequest, @@ -43,19 +44,20 @@ export const GET = async ( } export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { + const { additional_data, ...rest } = req.validatedBody const updatePromotions = updatePromotionsWorkflow(req.scope) const promotionsData = [ { id: req.params.id, - ...req.validatedBody, + ...rest, } as any, ] await updatePromotions.run({ - input: { promotionsData }, + input: { promotionsData, additional_data }, }) const promotion = await refetchPromotion( diff --git a/packages/medusa/src/api/admin/promotions/route.ts b/packages/medusa/src/api/admin/promotions/route.ts index 95e20da979..6a0e54f7ab 100644 --- a/packages/medusa/src/api/admin/promotions/route.ts +++ b/packages/medusa/src/api/admin/promotions/route.ts @@ -12,6 +12,7 @@ import { AdminCreatePromotionType, AdminGetPromotionsParamsType, } from "./validators" +import { AdditionalData } from "@medusajs/types" export const GET = async ( req: AuthenticatedMedusaRequest, @@ -39,14 +40,15 @@ export const GET = async ( } export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { + const { additional_data, ...rest } = req.validatedBody const createPromotions = createPromotionsWorkflow(req.scope) - const promotionsData = [req.validatedBody] as any + const promotionsData = [rest] as any const { result } = await createPromotions.run({ - input: { promotionsData }, + input: { promotionsData, additional_data }, }) const promotion = await refetchPromotion( diff --git a/packages/medusa/src/api/admin/promotions/validators.ts b/packages/medusa/src/api/admin/promotions/validators.ts index 8060dbd3da..2a8c8a8310 100644 --- a/packages/medusa/src/api/admin/promotions/validators.ts +++ b/packages/medusa/src/api/admin/promotions/validators.ts @@ -11,7 +11,7 @@ import { createOperatorMap, createSelectParams, } from "../../utils/validators" -import { AdminCreateCampaign } from "../campaigns/validators" +import { CreateCampaign } from "../campaigns/validators" export type AdminGetPromotionParamsType = z.infer< typeof AdminGetPromotionParams @@ -155,51 +155,67 @@ const promoRefinement = (promo) => { return true } -export type AdminCreatePromotionType = z.infer -const _AdminCreatePromotion = z +export type AdminCreatePromotionType = z.infer +export const CreatePromotion = z .object({ code: z.string(), is_automatic: z.boolean().optional(), type: z.nativeEnum(PromotionType), campaign_id: z.string().nullish(), - campaign: AdminCreateCampaign.optional(), + campaign: CreateCampaign.optional(), application_method: AdminCreateApplicationMethod, rules: z.array(AdminCreatePromotionRule).optional(), }) .strict() -export const AdminCreatePromotion = (customSchema?: ZodObject) => { - const schema = customSchema - ? _AdminCreatePromotion.merge(customSchema) - : _AdminCreatePromotion +export const AdminCreatePromotion = ( + additionalDataValidator?: ZodObject +) => { + 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 schema.refine(promoRefinement, { + return CreatePromotion.extend({ + additional_data: additionalDataValidator, + }).refine(promoRefinement, { message: "Buyget promotions require at least one buy rule and quantities to be defined", }) } -export type AdminUpdatePromotionType = z.infer -const _AdminUpdatePromotion = z +export type AdminUpdatePromotionType = z.infer +export const UpdatePromotion = z .object({ code: z.string().optional(), is_automatic: z.boolean().optional(), type: z.nativeEnum(PromotionType).optional(), campaign_id: z.string().nullish(), - campaign: AdminCreateCampaign.optional(), + campaign: CreateCampaign.optional(), application_method: AdminUpdateApplicationMethod.optional(), rules: z.array(AdminCreatePromotionRule).optional(), }) .strict() -export const AdminUpdatePromotion = (customSchema?: ZodObject) => { - const schema = customSchema - ? _AdminUpdatePromotion.merge(customSchema) - : _AdminUpdatePromotion +export const AdminUpdatePromotion = ( + additionalDataValidator?: ZodObject +) => { + 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 schema.refine(promoRefinement, { + return UpdatePromotion.extend({ + additional_data: additionalDataValidator, + }).refine(promoRefinement, { message: "Buyget promotions require at least one buy rule and quantities to be defined", })