diff --git a/packages/core/core-flows/src/order/workflows/cancel-order-fulfillment.ts b/packages/core/core-flows/src/order/workflows/cancel-order-fulfillment.ts index 7ab4547e93..237efa949d 100644 --- a/packages/core/core-flows/src/order/workflows/cancel-order-fulfillment.ts +++ b/packages/core/core-flows/src/order/workflows/cancel-order-fulfillment.ts @@ -1,4 +1,5 @@ import { + AdditionalData, BigNumberInput, FulfillmentDTO, OrderDTO, @@ -7,6 +8,8 @@ import { import { MedusaError, Modules } from "@medusajs/utils" import { WorkflowData, + WorkflowResponse, + createHook, createStep, createWorkflow, parallelize, @@ -109,8 +112,10 @@ export const cancelOrderFulfillmentWorkflowId = "cancel-order-fulfillment" export const cancelOrderFulfillmentWorkflow = createWorkflow( cancelOrderFulfillmentWorkflowId, ( - input: WorkflowData - ): WorkflowData => { + input: WorkflowData< + OrderWorkflow.CancelOrderFulfillmentWorkflowInput & AdditionalData + > + ) => { const order: OrderDTO & { fulfillments: FulfillmentDTO[] } = useRemoteQueryStep({ entry_point: "orders", @@ -153,5 +158,14 @@ export const cancelOrderFulfillmentWorkflow = createWorkflow( id: input.fulfillment_id, }, }) + + const orderFulfillmentCanceled = createHook("orderFulfillmentCanceled", { + fulfillment, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(void 0, { + hooks: [orderFulfillmentCanceled], + }) } ) diff --git a/packages/core/core-flows/src/order/workflows/cancel-order.ts b/packages/core/core-flows/src/order/workflows/cancel-order.ts index 65c46ac011..8df8e732be 100644 --- a/packages/core/core-flows/src/order/workflows/cancel-order.ts +++ b/packages/core/core-flows/src/order/workflows/cancel-order.ts @@ -7,6 +7,8 @@ import { import { MedusaError, deepFlatMap } from "@medusajs/utils" import { WorkflowData, + WorkflowResponse, + createHook, createStep, createWorkflow, parallelize, @@ -77,9 +79,7 @@ const validateOrder = createStep( export const cancelOrderWorkflowId = "cancel-order" export const cancelOrderWorkflow = createWorkflow( cancelOrderWorkflowId, - ( - input: WorkflowData - ): WorkflowData => { + (input: WorkflowData) => { const order: OrderDTO & { fulfillments: FulfillmentDTO[] } = useRemoteQueryStep({ entry_point: "orders", @@ -118,5 +118,13 @@ export const cancelOrderWorkflow = createWorkflow( cancelPaymentStep({ paymentIds }), cancelOrdersStep({ orderIds: [order.id] }) ) + + const orderCanceled = createHook("orderCanceled", { + order, + }) + + return new WorkflowResponse(void 0, { + hooks: [orderCanceled], + }) } ) diff --git a/packages/core/core-flows/src/order/workflows/complete-orders.ts b/packages/core/core-flows/src/order/workflows/complete-orders.ts index 9725fa1c64..44739c59e8 100644 --- a/packages/core/core-flows/src/order/workflows/complete-orders.ts +++ b/packages/core/core-flows/src/order/workflows/complete-orders.ts @@ -1,21 +1,28 @@ -import { OrderDTO } from "@medusajs/types" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, } from "@medusajs/workflows-sdk" import { completeOrdersStep } from "../steps" +import { AdditionalData } from "@medusajs/types" type CompleteOrdersStepInput = { orderIds: string[] -} +} & AdditionalData export const completeOrderWorkflowId = "complete-order-workflow" export const completeOrderWorkflow = createWorkflow( completeOrderWorkflowId, - ( - input: WorkflowData - ): WorkflowResponse => { - return new WorkflowResponse(completeOrdersStep(input)) + (input: WorkflowData) => { + const completedOrders = completeOrdersStep(input) + const ordersCompleted = createHook("ordersCompleted", { + orders: completedOrders, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(completedOrders, { + hooks: [ordersCompleted], + }) } ) diff --git a/packages/core/core-flows/src/order/workflows/create-fulfillment.ts b/packages/core/core-flows/src/order/workflows/create-fulfillment.ts index 194c1cedf9..fc4dc87db4 100644 --- a/packages/core/core-flows/src/order/workflows/create-fulfillment.ts +++ b/packages/core/core-flows/src/order/workflows/create-fulfillment.ts @@ -1,6 +1,6 @@ import { + AdditionalData, BigNumberInput, - FulfillmentDTO, FulfillmentWorkflow, OrderDTO, OrderLineItemDTO, @@ -11,6 +11,7 @@ import { MathBN, MedusaError, Modules } from "@medusajs/utils" import { WorkflowData, WorkflowResponse, + createHook, createStep, createWorkflow, parallelize, @@ -204,8 +205,10 @@ export const createOrderFulfillmentWorkflowId = "create-order-fulfillment" export const createOrderFulfillmentWorkflow = createWorkflow( createOrderFulfillmentWorkflowId, ( - input: WorkflowData - ): WorkflowResponse => { + input: WorkflowData< + OrderWorkflow.CreateOrderFulfillmentWorkflowInput & AdditionalData + > + ) => { const order: OrderDTO = useRemoteQueryStep({ entry_point: "orders", fields: [ @@ -323,7 +326,14 @@ export const createOrderFulfillmentWorkflow = createWorkflow( deleteReservationsStep(toDelete) ) + const fulfillmentCreated = createHook("fulfillmentCreated", { + fulfillment, + additional_data: input.additional_data, + }) + // trigger event OrderModuleService.Events.FULFILLMENT_CREATED - return new WorkflowResponse(fulfillment) + return new WorkflowResponse(fulfillment, { + hooks: [fulfillmentCreated], + }) } ) diff --git a/packages/core/core-flows/src/order/workflows/create-orders.ts b/packages/core/core-flows/src/order/workflows/create-orders.ts index b984e3d728..8ab4758ca8 100644 --- a/packages/core/core-flows/src/order/workflows/create-orders.ts +++ b/packages/core/core-flows/src/order/workflows/create-orders.ts @@ -1,8 +1,9 @@ -import { CreateOrderDTO, OrderDTO } from "@medusajs/types" +import { AdditionalData, CreateOrderDTO } from "@medusajs/types" import { MathBN, MedusaError, isPresent } from "@medusajs/utils" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, parallelize, transform, @@ -85,7 +86,7 @@ function getOrderInput(data) { export const createOrdersWorkflowId = "create-orders" export const createOrdersWorkflow = createWorkflow( createOrdersWorkflowId, - (input: WorkflowData): WorkflowResponse => { + (input: WorkflowData) => { const variantIds = transform({ input }, (data) => { return (data.input.items ?? []) .map((item) => item.variant_id) @@ -176,7 +177,13 @@ export const createOrdersWorkflow = createWorkflow( */ updateOrderTaxLinesStep({ order_id: order.id }) + const orderCreated = createHook("orderCreated", { + order, + additional_data: input.additional_data, + }) - return new WorkflowResponse(order) + return new WorkflowResponse(order, { + hooks: [orderCreated], + }) } ) diff --git a/packages/core/core-flows/src/order/workflows/create-shipment.ts b/packages/core/core-flows/src/order/workflows/create-shipment.ts index 42c8e34202..2658960386 100644 --- a/packages/core/core-flows/src/order/workflows/create-shipment.ts +++ b/packages/core/core-flows/src/order/workflows/create-shipment.ts @@ -1,7 +1,14 @@ -import { FulfillmentDTO, OrderDTO, OrderWorkflow } from "@medusajs/types" +import { + AdditionalData, + FulfillmentDTO, + OrderDTO, + OrderWorkflow, +} from "@medusajs/types" import { FulfillmentEvents, Modules } from "@medusajs/utils" import { WorkflowData, + WorkflowResponse, + createHook, createStep, createWorkflow, parallelize, @@ -70,8 +77,10 @@ export const createOrderShipmentWorkflowId = "create-order-shipment" export const createOrderShipmentWorkflow = createWorkflow( createOrderShipmentWorkflowId, ( - input: WorkflowData - ): WorkflowData => { + input: WorkflowData< + OrderWorkflow.CreateOrderShipmentWorkflowInput & AdditionalData + > + ) => { const order: OrderDTO = useRemoteQueryStep({ entry_point: "orders", fields: [ @@ -112,5 +121,14 @@ export const createOrderShipmentWorkflow = createWorkflow( eventName: FulfillmentEvents.SHIPMENT_CREATED, data: { id: shipment.id }, }) + + const shipmentCreated = createHook("shipmentCreated", { + shipment, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(void 0, { + hooks: [shipmentCreated], + }) } ) diff --git a/packages/medusa/src/api/admin/draft-orders/route.ts b/packages/medusa/src/api/admin/draft-orders/route.ts index 6a459200bf..747ae18e7f 100644 --- a/packages/medusa/src/api/admin/draft-orders/route.ts +++ b/packages/medusa/src/api/admin/draft-orders/route.ts @@ -11,7 +11,7 @@ import { } from "../../../types/routing" import { AdminCreateDraftOrderType } from "./validators" import { refetchOrder } from "./helpers" -import { CreateOrderDTO } from "@medusajs/types" +import { AdditionalData, CreateOrderDTO } from "@medusajs/types" export const GET = async (req: MedusaRequest, res: MedusaResponse) => { const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) @@ -39,7 +39,7 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => { } export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const input = req.validatedBody @@ -48,7 +48,7 @@ export const POST = async ( no_notification: !!input.no_notification_order, status: OrderStatus.DRAFT, is_draft_order: true, - } as CreateOrderDTO + } as CreateOrderDTO & AdditionalData const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) diff --git a/packages/medusa/src/api/admin/draft-orders/validators.ts b/packages/medusa/src/api/admin/draft-orders/validators.ts index a008044e1a..b482a22703 100644 --- a/packages/medusa/src/api/admin/draft-orders/validators.ts +++ b/packages/medusa/src/api/admin/draft-orders/validators.ts @@ -1,6 +1,10 @@ -import { z, ZodObject } from "zod" +import { z } from "zod" import { AddressPayload, BigNumberInput } from "../../utils/common-validators" -import { createFindParams, createSelectParams } from "../../utils/validators" +import { + createFindParams, + createSelectParams, + WithAdditionalData, +} from "../../utils/validators" export type AdminGetOrderParamsType = z.infer export const AdminGetOrderParams = createSelectParams() @@ -49,8 +53,8 @@ const Item = z return true }) -export type AdminCreateDraftOrderType = z.infer -const _AdminCreateDraftOrder = z +export type AdminCreateDraftOrderType = z.infer +const CreateDraftOrder = z .object({ status: z.nativeEnum(Status).optional(), sales_channel_id: z.string().nullish(), @@ -68,19 +72,18 @@ const _AdminCreateDraftOrder = z }) .strict() -export const AdminCreateDraftOrder = (customSchema?: ZodObject) => { - const schema = customSchema - ? _AdminCreateDraftOrder.merge(customSchema) - : _AdminCreateDraftOrder +export const AdminCreateDraftOrder = WithAdditionalData( + CreateDraftOrder, + (schema) => { + return schema.refine( + (data) => { + if (!data.email && !data.customer_id) { + return false + } - return schema.refine( - (data) => { - if (!data.email && !data.customer_id) { - return false - } - - return true - }, - { message: "Either email or customer_id must be provided" } - ) -} + return true + }, + { message: "Either email or customer_id must be provided" } + ) + } +) diff --git a/packages/medusa/src/api/admin/orders/[id]/complete/route.ts b/packages/medusa/src/api/admin/orders/[id]/complete/route.ts index f340b293be..578e3622b9 100644 --- a/packages/medusa/src/api/admin/orders/[id]/complete/route.ts +++ b/packages/medusa/src/api/admin/orders/[id]/complete/route.ts @@ -1,3 +1,4 @@ +import { AdditionalData } from "@medusajs/types" import { completeOrderWorkflow } from "@medusajs/core-flows" import { ContainerRegistrationKeys, @@ -10,14 +11,17 @@ import { import { AdminCompleteOrderType } from "../../validators" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const { id } = req.params await completeOrderWorkflow(req.scope).run({ - input: { orderIds: [req.validatedBody.order_id] }, + input: { + orderIds: [req.validatedBody.order_id], + additional_data: req.validatedBody.additional_data, + }, }) const queryObject = remoteQueryObjectFromString({ diff --git a/packages/medusa/src/api/admin/orders/[id]/fulfillments/[fulfillment_id]/cancel/route.ts b/packages/medusa/src/api/admin/orders/[id]/fulfillments/[fulfillment_id]/cancel/route.ts index 88da6c1a18..e6c7ce0900 100644 --- a/packages/medusa/src/api/admin/orders/[id]/fulfillments/[fulfillment_id]/cancel/route.ts +++ b/packages/medusa/src/api/admin/orders/[id]/fulfillments/[fulfillment_id]/cancel/route.ts @@ -8,9 +8,12 @@ import { MedusaResponse, } from "../../../../../../../types/routing" import { AdminOrderCancelFulfillmentType } from "../../../../validators" +import { AdditionalData } from "@medusajs/types" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest< + AdminOrderCancelFulfillmentType & AdditionalData + >, res: MedusaResponse ) => { const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) diff --git a/packages/medusa/src/api/admin/orders/[id]/fulfillments/[fulfillment_id]/shipments/route.ts b/packages/medusa/src/api/admin/orders/[id]/fulfillments/[fulfillment_id]/shipments/route.ts index cca297a96f..7fbe8904b7 100644 --- a/packages/medusa/src/api/admin/orders/[id]/fulfillments/[fulfillment_id]/shipments/route.ts +++ b/packages/medusa/src/api/admin/orders/[id]/fulfillments/[fulfillment_id]/shipments/route.ts @@ -8,9 +8,12 @@ import { MedusaResponse, } from "../../../../../../../types/routing" import { AdminOrderCreateShipmentType } from "../../../../validators" +import { AdditionalData } from "@medusajs/types" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest< + AdminOrderCreateShipmentType & AdditionalData + >, res: MedusaResponse ) => { const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) diff --git a/packages/medusa/src/api/admin/orders/[id]/fulfillments/route.ts b/packages/medusa/src/api/admin/orders/[id]/fulfillments/route.ts index 453d4cbb17..0999b7ec18 100644 --- a/packages/medusa/src/api/admin/orders/[id]/fulfillments/route.ts +++ b/packages/medusa/src/api/admin/orders/[id]/fulfillments/route.ts @@ -8,9 +8,12 @@ import { MedusaResponse, } from "../../../../../types/routing" import { AdminOrderCreateFulfillmentType } from "../../validators" +import { AdditionalData } from "@medusajs/types" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest< + AdminOrderCreateFulfillmentType & AdditionalData + >, res: MedusaResponse ) => { const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) diff --git a/packages/medusa/src/api/admin/orders/validators.ts b/packages/medusa/src/api/admin/orders/validators.ts index 516cd53403..b572420670 100644 --- a/packages/medusa/src/api/admin/orders/validators.ts +++ b/packages/medusa/src/api/admin/orders/validators.ts @@ -3,6 +3,7 @@ import { createFindParams, createOperatorMap, createSelectParams, + WithAdditionalData, } from "../../utils/validators" export const AdminGetOrdersOrderParams = createSelectParams().merge( @@ -42,26 +43,29 @@ export const AdminArchiveOrder = z.object({ }) export type AdminArchiveOrderType = z.infer -export const AdminCompleteOrder = z.object({ +export type AdminCompleteOrderType = z.infer +export const CompleteOrder = z.object({ order_id: z.string(), }) -export type AdminCompleteOrderType = z.infer +export const AdminCompleteOrder = WithAdditionalData(CompleteOrder) const Item = z.object({ id: z.string(), quantity: z.number(), }) -export const AdminOrderCreateFulfillment = z.object({ +export type AdminOrderCreateFulfillmentType = z.infer< + typeof OrderCreateFulfillment +> +export const OrderCreateFulfillment = z.object({ items: z.array(Item), location_id: z.string().nullish(), no_notification: z.boolean().optional(), metadata: z.record(z.unknown()).nullish(), }) - -export type AdminOrderCreateFulfillmentType = z.infer< - typeof AdminOrderCreateFulfillment -> +export const AdminOrderCreateFulfillment = WithAdditionalData( + OrderCreateFulfillment +) const Label = z.object({ tracking_number: z.string(), @@ -69,21 +73,21 @@ const Label = z.object({ label_url: z.string(), }) -export const AdminOrderCreateShipment = z.object({ +export type AdminOrderCreateShipmentType = z.infer +export const OrderCreateShipment = z.object({ items: z.array(Item), labels: z.array(Label).optional(), no_notification: z.boolean().optional(), metadata: z.record(z.unknown()).nullish(), }) - -export type AdminOrderCreateShipmentType = z.infer< - typeof AdminOrderCreateShipment -> - -export const AdminOrderCancelFulfillment = z.object({ - no_notification: z.boolean().optional(), -}) +export const AdminOrderCreateShipment = WithAdditionalData(OrderCreateShipment) export type AdminOrderCancelFulfillmentType = z.infer< - typeof AdminOrderCancelFulfillment + typeof OrderCancelFulfillment > +export const OrderCancelFulfillment = z.object({ + no_notification: z.boolean().optional(), +}) +export const AdminOrderCancelFulfillment = WithAdditionalData( + OrderCancelFulfillment +) diff --git a/packages/medusa/src/api/utils/validators.ts b/packages/medusa/src/api/utils/validators.ts index 82f9ed0f8f..c3aff0abb0 100644 --- a/packages/medusa/src/api/utils/validators.ts +++ b/packages/medusa/src/api/utils/validators.ts @@ -1,19 +1,27 @@ -import { z, ZodObject } from "zod" +import { z, ZodEffects, ZodObject } from "zod" /** * Wraps the original schema to a function to accept and merge * additional_data schema */ -export const WithAdditionalData = (originalSchema: ZodObject) => { +export const WithAdditionalData = >( + originalSchema: T, + modifyCallback?: (schema: T) => ZodObject | ZodEffects +) => { return (additionalDataValidator?: ZodObject) => { + let schema: ZodObject + if (!additionalDataValidator) { - return originalSchema.extend({ + schema = originalSchema.extend({ additional_data: z.record(z.unknown()).nullish(), }) + } else { + schema = originalSchema.extend({ + additional_data: additionalDataValidator, + }) } - return originalSchema.extend({ - additional_data: additionalDataValidator, - }) + + return modifyCallback ? modifyCallback(schema as T) : schema } }