diff --git a/packages/core/core-flows/src/customer/workflows/create-addresses.ts b/packages/core/core-flows/src/customer/workflows/create-addresses.ts index f3df0d5f15..c3cb742078 100644 --- a/packages/core/core-flows/src/customer/workflows/create-addresses.ts +++ b/packages/core/core-flows/src/customer/workflows/create-addresses.ts @@ -1,7 +1,8 @@ -import { CreateCustomerAddressDTO, CustomerAddressDTO } from "@medusajs/types" +import { AdditionalData, CreateCustomerAddressDTO } from "@medusajs/types" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, parallelize, transform, @@ -12,14 +13,12 @@ import { maybeUnsetDefaultShippingAddressesStep, } from "../steps" -type WorkflowInput = { addresses: CreateCustomerAddressDTO[] } +type WorkflowInput = { addresses: CreateCustomerAddressDTO[] } & AdditionalData export const createCustomerAddressesWorkflowId = "create-customer-addresses" export const createCustomerAddressesWorkflow = createWorkflow( createCustomerAddressesWorkflowId, - ( - input: WorkflowData - ): WorkflowResponse => { + (input: WorkflowData) => { const unsetInput = transform(input, (data) => ({ create: data.addresses, })) @@ -29,6 +28,14 @@ export const createCustomerAddressesWorkflow = createWorkflow( maybeUnsetDefaultBillingAddressesStep(unsetInput) ) - return new WorkflowResponse(createCustomerAddressesStep(input.addresses)) + const createdAddresses = createCustomerAddressesStep(input.addresses) + const addressesCreated = createHook("addressesCreated", { + addresses: createdAddresses, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(createdAddresses, { + hooks: [addressesCreated], + }) } ) diff --git a/packages/core/core-flows/src/customer/workflows/create-customers.ts b/packages/core/core-flows/src/customer/workflows/create-customers.ts index b4f24dca15..7a6974b8aa 100644 --- a/packages/core/core-flows/src/customer/workflows/create-customers.ts +++ b/packages/core/core-flows/src/customer/workflows/create-customers.ts @@ -1,17 +1,27 @@ -import { CustomerDTO, CreateCustomerDTO } from "@medusajs/types" +import { CreateCustomerDTO, AdditionalData } from "@medusajs/types" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, } from "@medusajs/workflows-sdk" import { createCustomersStep } from "../steps" -type WorkflowInput = { customersData: CreateCustomerDTO[] } +type WorkflowInput = { customersData: CreateCustomerDTO[] } & AdditionalData export const createCustomersWorkflowId = "create-customers" + export const createCustomersWorkflow = createWorkflow( createCustomersWorkflowId, - (input: WorkflowData): WorkflowResponse => { - return new WorkflowResponse(createCustomersStep(input.customersData)) + (input: WorkflowData) => { + const createdCustomers = createCustomersStep(input.customersData) + const customersCreated = createHook("customersCreated", { + customers: createdCustomers, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(createdCustomers, { + hooks: [customersCreated], + }) } ) diff --git a/packages/core/core-flows/src/customer/workflows/delete-addresses.ts b/packages/core/core-flows/src/customer/workflows/delete-addresses.ts index 3a0e2727b4..77d4f15345 100644 --- a/packages/core/core-flows/src/customer/workflows/delete-addresses.ts +++ b/packages/core/core-flows/src/customer/workflows/delete-addresses.ts @@ -1,4 +1,9 @@ -import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" +import { + WorkflowData, + WorkflowResponse, + createHook, + createWorkflow, +} from "@medusajs/workflows-sdk" import { deleteCustomerAddressesStep } from "../steps" type WorkflowInput = { ids: string[] } @@ -6,7 +11,14 @@ type WorkflowInput = { ids: string[] } export const deleteCustomerAddressesWorkflowId = "delete-customer-addresses" export const deleteCustomerAddressesWorkflow = createWorkflow( deleteCustomerAddressesWorkflowId, - (input: WorkflowData): WorkflowData => { - return deleteCustomerAddressesStep(input.ids) + (input: WorkflowData) => { + const deletedAddresses = deleteCustomerAddressesStep(input.ids) + const addressesDeleted = createHook("addressesDeleted", { + ids: input.ids, + }) + + return new WorkflowResponse(deletedAddresses, { + hooks: [addressesDeleted], + }) } ) diff --git a/packages/core/core-flows/src/customer/workflows/delete-customers.ts b/packages/core/core-flows/src/customer/workflows/delete-customers.ts index 2af349498d..d6128bdc04 100644 --- a/packages/core/core-flows/src/customer/workflows/delete-customers.ts +++ b/packages/core/core-flows/src/customer/workflows/delete-customers.ts @@ -1,4 +1,9 @@ -import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" +import { + WorkflowData, + WorkflowResponse, + createHook, + createWorkflow, +} from "@medusajs/workflows-sdk" import { deleteCustomersStep } from "../steps" type WorkflowInput = { ids: string[] } @@ -6,7 +11,14 @@ type WorkflowInput = { ids: string[] } export const deleteCustomersWorkflowId = "delete-customers" export const deleteCustomersWorkflow = createWorkflow( deleteCustomersWorkflowId, - (input: WorkflowData): WorkflowData => { - return deleteCustomersStep(input.ids) + (input: WorkflowData) => { + const deletedCustomers = deleteCustomersStep(input.ids) + const customersDeleted = createHook("customersDeleted", { + ids: input.ids, + }) + + return new WorkflowResponse(deletedCustomers, { + hooks: [customersDeleted], + }) } ) diff --git a/packages/core/core-flows/src/customer/workflows/update-addresses.ts b/packages/core/core-flows/src/customer/workflows/update-addresses.ts index 2cfa44338c..fb1fe63018 100644 --- a/packages/core/core-flows/src/customer/workflows/update-addresses.ts +++ b/packages/core/core-flows/src/customer/workflows/update-addresses.ts @@ -1,11 +1,12 @@ import { FilterableCustomerAddressProps, - CustomerAddressDTO, UpdateCustomerAddressDTO, + AdditionalData, } from "@medusajs/types" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, parallelize, transform, @@ -19,14 +20,12 @@ import { type WorkflowInput = { selector: FilterableCustomerAddressProps update: UpdateCustomerAddressDTO -} +} & AdditionalData export const updateCustomerAddressesWorkflowId = "update-customer-addresses" export const updateCustomerAddressesWorkflow = createWorkflow( updateCustomerAddressesWorkflowId, - ( - input: WorkflowData - ): WorkflowResponse => { + (input: WorkflowData) => { const unsetInput = transform(input, (data) => ({ update: data, })) @@ -36,6 +35,14 @@ export const updateCustomerAddressesWorkflow = createWorkflow( maybeUnsetDefaultBillingAddressesStep(unsetInput) ) - return new WorkflowResponse(updateCustomerAddressesStep(input)) + const updatedAddresses = updateCustomerAddressesStep(input) + const addressesUpdated = createHook("addressesUpdated", { + addresses: updatedAddresses, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(updatedAddresses, { + hooks: [addressesUpdated], + }) } ) diff --git a/packages/core/core-flows/src/customer/workflows/update-customers.ts b/packages/core/core-flows/src/customer/workflows/update-customers.ts index 8ee92f2991..04d2b6e72f 100644 --- a/packages/core/core-flows/src/customer/workflows/update-customers.ts +++ b/packages/core/core-flows/src/customer/workflows/update-customers.ts @@ -1,11 +1,12 @@ import { - CustomerDTO, + AdditionalData, CustomerUpdatableFields, FilterableCustomerProps, } from "@medusajs/types" import { WorkflowData, WorkflowResponse, + createHook, createWorkflow, } from "@medusajs/workflows-sdk" import { updateCustomersStep } from "../steps" @@ -13,14 +14,22 @@ import { updateCustomersStep } from "../steps" type UpdateCustomersStepInput = { selector: FilterableCustomerProps update: CustomerUpdatableFields -} +} & AdditionalData type WorkflowInput = UpdateCustomersStepInput export const updateCustomersWorkflowId = "update-customers" export const updateCustomersWorkflow = createWorkflow( updateCustomersWorkflowId, - (input: WorkflowData): WorkflowResponse => { - return new WorkflowResponse(updateCustomersStep(input)) + (input: WorkflowData) => { + const updatedCustomers = updateCustomersStep(input) + const customersUpdated = createHook("customersUpdated", { + customers: updatedCustomers, + additional_data: input.additional_data, + }) + + return new WorkflowResponse(updatedCustomers, { + hooks: [customersUpdated], + }) } ) diff --git a/packages/medusa/src/api/admin/customers/[id]/addresses/[address_id]/route.ts b/packages/medusa/src/api/admin/customers/[id]/addresses/[address_id]/route.ts index e15203000d..6b5d9fab88 100644 --- a/packages/medusa/src/api/admin/customers/[id]/addresses/[address_id]/route.ts +++ b/packages/medusa/src/api/admin/customers/[id]/addresses/[address_id]/route.ts @@ -13,6 +13,7 @@ import { } from "@medusajs/utils" import { AdminCreateCustomerAddressType } from "../../../validators" import { refetchCustomer } from "../../../helpers" +import { AdditionalData } from "@medusajs/types" export const GET = async ( req: AuthenticatedMedusaRequest, @@ -33,14 +34,19 @@ export const GET = async ( } export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest< + AdminCreateCustomerAddressType & AdditionalData + >, res: MedusaResponse ) => { + const { additional_data, ...rest } = req.validatedBody + const updateAddresses = updateCustomerAddressesWorkflow(req.scope) await updateAddresses.run({ input: { selector: { id: req.params.address_id, customer_id: req.params.id }, - update: req.validatedBody, + update: rest, + additional_data, }, }) diff --git a/packages/medusa/src/api/admin/customers/[id]/addresses/route.ts b/packages/medusa/src/api/admin/customers/[id]/addresses/route.ts index 2038b91115..63d995d866 100644 --- a/packages/medusa/src/api/admin/customers/[id]/addresses/route.ts +++ b/packages/medusa/src/api/admin/customers/[id]/addresses/route.ts @@ -9,6 +9,7 @@ import { } from "@medusajs/utils" import { AdminCreateCustomerAddressType } from "../../validators" import { refetchCustomer } from "../../helpers" +import { AdditionalData } from "@medusajs/types" export const GET = async ( req: AuthenticatedMedusaRequest, @@ -37,20 +38,23 @@ export const GET = async ( } export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest< + AdminCreateCustomerAddressType & AdditionalData + >, res: MedusaResponse ) => { + const { additional_data, ...rest } = req.validatedBody const customerId = req.params.id const createAddresses = createCustomerAddressesWorkflow(req.scope) const addresses = [ { - ...req.validatedBody, + ...rest, customer_id: customerId, }, ] await createAddresses.run({ - input: { addresses }, + input: { addresses, additional_data }, }) const customer = await refetchCustomer( diff --git a/packages/medusa/src/api/admin/customers/[id]/route.ts b/packages/medusa/src/api/admin/customers/[id]/route.ts index dbbfbf3f79..40579c8452 100644 --- a/packages/medusa/src/api/admin/customers/[id]/route.ts +++ b/packages/medusa/src/api/admin/customers/[id]/route.ts @@ -2,7 +2,7 @@ import { deleteCustomersWorkflow, updateCustomersWorkflow, } from "@medusajs/core-flows" -import { AdminCustomer } from "@medusajs/types" +import { AdditionalData, AdminCustomer } from "@medusajs/types" import { MedusaError } from "@medusajs/utils" import { AuthenticatedMedusaRequest, @@ -32,13 +32,16 @@ export const GET = async ( } export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse<{ customer: AdminCustomer }> ) => { + const { additional_data, ...rest } = req.validatedBody + await updateCustomersWorkflow(req.scope).run({ input: { selector: { id: req.params.id }, - update: req.validatedBody, + update: rest, + additional_data, }, }) diff --git a/packages/medusa/src/api/admin/customers/route.ts b/packages/medusa/src/api/admin/customers/route.ts index 183001fe0c..8aec2cc9f3 100644 --- a/packages/medusa/src/api/admin/customers/route.ts +++ b/packages/medusa/src/api/admin/customers/route.ts @@ -1,6 +1,10 @@ import { createCustomersWorkflow } from "@medusajs/core-flows" -import { AdminCustomer, PaginatedResponse } from "@medusajs/types" +import { + AdditionalData, + AdminCustomer, + PaginatedResponse, +} from "@medusajs/types" import { ContainerRegistrationKeys, remoteQueryObjectFromString, @@ -38,20 +42,21 @@ export const GET = async ( } export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse<{ customer: AdminCustomer }> ) => { + const { additional_data, ...rest } = req.validatedBody const createCustomers = createCustomersWorkflow(req.scope) const customersData = [ { - ...req.validatedBody, + ...rest, created_by: req.auth_context.actor_id, }, ] const { result } = await createCustomers.run({ - input: { customersData }, + input: { customersData, additional_data }, }) const customer = await refetchCustomer( diff --git a/packages/medusa/src/api/admin/customers/validators.ts b/packages/medusa/src/api/admin/customers/validators.ts index 0b6ff2acc6..09dffbdb1b 100644 --- a/packages/medusa/src/api/admin/customers/validators.ts +++ b/packages/medusa/src/api/admin/customers/validators.ts @@ -1,4 +1,4 @@ -import { z } from "zod" +import { z, ZodObject } from "zod" import { createFindParams, createOperatorMap, @@ -42,7 +42,7 @@ export const AdminCustomersParams = createFindParams({ }) ) -export const AdminCreateCustomer = z.object({ +export const CreateCustomer = z.object({ email: z.string().email().nullish(), company_name: z.string().nullish(), first_name: z.string().nullish(), @@ -50,8 +50,21 @@ export const AdminCreateCustomer = z.object({ phone: z.string().nullish(), metadata: z.record(z.unknown()).nullish(), }) +export const AdminCreateCustomer = ( + additionalDataValidator?: ZodObject +) => { + if (!additionalDataValidator) { + return CreateCustomer.extend({ + additional_data: z.record(z.unknown()).nullish(), + }) + } -export const AdminUpdateCustomer = z.object({ + return CreateCustomer.extend({ + additional_data: additionalDataValidator, + }) +} + +export const UpdateCustomer = z.object({ email: z.string().email().nullish(), company_name: z.string().nullish(), first_name: z.string().nullish(), @@ -59,8 +72,21 @@ export const AdminUpdateCustomer = z.object({ phone: z.string().nullish(), metadata: z.record(z.unknown()).nullish(), }) +export const AdminUpdateCustomer = ( + additionalDataValidator?: ZodObject +) => { + if (!additionalDataValidator) { + return UpdateCustomer.extend({ + additional_data: z.record(z.unknown()).nullish(), + }) + } -export const AdminCreateCustomerAddress = z.object({ + return UpdateCustomer.extend({ + additional_data: additionalDataValidator, + }) +} + +export const CreateCustomerAddress = z.object({ address_name: z.string().nullish(), is_default_shipping: z.boolean().optional(), is_default_billing: z.boolean().optional(), @@ -76,6 +102,19 @@ export const AdminCreateCustomerAddress = z.object({ phone: z.string().nullish(), metadata: z.record(z.unknown()).nullish(), }) +export const AdminCreateCustomerAddress = ( + additionalDataValidator?: ZodObject +) => { + if (!additionalDataValidator) { + return CreateCustomerAddress.extend({ + additional_data: z.record(z.unknown()).nullish(), + }) + } + + return CreateCustomerAddress.extend({ + additional_data: additionalDataValidator, + }) +} export const AdminUpdateCustomerAddress = AdminCreateCustomerAddress @@ -95,8 +134,8 @@ export const AdminCustomerAddressesParams = createFindParams({ export type AdminCustomerParamsType = z.infer export type AdminCustomersParamsType = z.infer -export type AdminCreateCustomerType = z.infer -export type AdminUpdateCustomerType = z.infer +export type AdminCreateCustomerType = z.infer +export type AdminUpdateCustomerType = z.infer export type AdminCreateCustomerAddressType = z.infer< - typeof AdminCreateCustomerAddress + typeof CreateCustomerAddress >