From 6ae2ce8ed9fe3b84f50428b13f5ee1048ec73f0c Mon Sep 17 00:00:00 2001 From: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com> Date: Tue, 9 Dec 2025 18:54:41 +0530 Subject: [PATCH] fix: workflow email is not sending on form submission (#25722) * fix: email not sending on form submission * Remove handleCheckoutSessionExpired function Removed the handleCheckoutSessionExpired function and its registration in webhookHandlers. --- .../lib/service/EmailWorkflowService.test.ts | 118 ++++++++++++++++++ .../lib/service/EmailWorkflowService.ts | 11 +- 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/packages/features/ee/workflows/lib/service/EmailWorkflowService.test.ts b/packages/features/ee/workflows/lib/service/EmailWorkflowService.test.ts index b11f5d7cc1..b1e625755b 100644 --- a/packages/features/ee/workflows/lib/service/EmailWorkflowService.test.ts +++ b/packages/features/ee/workflows/lib/service/EmailWorkflowService.test.ts @@ -381,4 +381,122 @@ describe("EmailWorkflowService", () => { expect(result.sendTo.length).toBe(1); }); }); + + describe("generateParametersToBuildEmailWorkflowContent - Form Data", () => { + const mockCommonScheduleFunctionParams = { + triggerEvent: WorkflowTriggerEvents.FORM_SUBMITTED, + timeSpan: { + time: null, + timeUnit: null, + }, + workflowStepId: 1, + template: WorkflowTemplates.REMINDER, + userId: 1, + teamId: null, + seatReferenceUid: undefined, + verifiedAt: new Date(), + creditCheckFn: vi.fn().mockResolvedValue(true), + }; + + const mockFormData = { + responses: { + "contact person": { + value: "Jane Smith", + response: "Jane Smith", + }, + email: { + value: "jane@example.com", + response: "jane@example.com", + }, + }, + routedEventTypeId: null, + user: { + email: "user@test.com", + timeFormat: 12, + locale: "en", + }, + }; + + test("should work with EMAIL_ADDRESS action and formData (no evt)", async () => { + const mockWorkflowStep = { + id: 1, + action: WorkflowActions.EMAIL_ADDRESS, + verifiedAt: new Date(), + sendTo: "recipient@example.com", + template: WorkflowTemplates.REMINDER, + reminderBody: null, + emailSubject: null, + sender: null, + includeCalendarEvent: false, + numberVerificationPending: false, + numberRequired: false, + }; + + const result = await emailWorkflowService.generateParametersToBuildEmailWorkflowContent({ + formData: mockFormData, + workflowStep: mockWorkflowStep, + workflow: { userId: 1 }, + commonScheduleFunctionParams: mockCommonScheduleFunctionParams, + hideBranding: false, + }); + + expect(result.sendTo).toEqual(["recipient@example.com"]); + expect(result.formData).toEqual(mockFormData); + expect(result.evt).toBeUndefined(); + }); + + test("should work with EMAIL_ATTENDEE action and formData (no evt)", async () => { + const mockWorkflowStep = { + id: 1, + action: WorkflowActions.EMAIL_ATTENDEE, + verifiedAt: new Date(), + sendTo: null, + template: WorkflowTemplates.REMINDER, + reminderBody: null, + emailSubject: null, + sender: null, + includeCalendarEvent: false, + numberVerificationPending: false, + numberRequired: false, + }; + + const result = await emailWorkflowService.generateParametersToBuildEmailWorkflowContent({ + formData: mockFormData, + workflowStep: mockWorkflowStep, + workflow: { userId: 1 }, + commonScheduleFunctionParams: mockCommonScheduleFunctionParams, + hideBranding: false, + }); + + // Should extract email from formData responses + expect(result.sendTo).toEqual(["jane@example.com"]); + expect(result.formData).toEqual(mockFormData); + expect(result.evt).toBeUndefined(); + }); + + test("should throw error if neither evt nor formData is provided", async () => { + const mockWorkflowStep = { + id: 1, + action: WorkflowActions.EMAIL_ADDRESS, + verifiedAt: new Date(), + sendTo: "recipient@example.com", + template: WorkflowTemplates.REMINDER, + reminderBody: null, + emailSubject: null, + sender: null, + includeCalendarEvent: false, + numberVerificationPending: false, + numberRequired: false, + }; + + await expect( + emailWorkflowService.generateParametersToBuildEmailWorkflowContent({ + workflowStep: mockWorkflowStep, + workflow: { userId: 1 }, + commonScheduleFunctionParams: mockCommonScheduleFunctionParams, + hideBranding: false, + }) + ).rejects.toThrow("Either evt or formData must be provided"); + }); + }); }); diff --git a/packages/features/ee/workflows/lib/service/EmailWorkflowService.ts b/packages/features/ee/workflows/lib/service/EmailWorkflowService.ts index 32e316edb1..4b55b4dd67 100644 --- a/packages/features/ee/workflows/lib/service/EmailWorkflowService.ts +++ b/packages/features/ee/workflows/lib/service/EmailWorkflowService.ts @@ -208,11 +208,15 @@ export class EmailWorkflowService { } } - // The evt builder already validates the bookerUrl exists - if (!evt || typeof evt.bookerUrl !== "string") { + // Only check for bookerUrl when evt is provided (not for form submissions) + if (evt && typeof evt.bookerUrl !== "string") { throw new Error("bookerUrl not a part of the evt"); } + if (!evt && !formData) { + throw new Error("Either evt or formData must be provided"); + } + const contextData: WorkflowContextData = evt ? { evt: evt as BookingInfo } : { formData: formData as FormSubmissionData }; @@ -311,7 +315,8 @@ export class EmailWorkflowService { organizerEmail: evt.organizer.email, sendToEmail: sendTo[0], }); - const meetingUrl = getVideoCallUrlFromCalEvent(evt) || bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl; + const meetingUrl = + getVideoCallUrlFromCalEvent(evt) || bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl; const variables: VariablesType = { eventName: evt.title || "", organizerName: evt.organizer.name,