fix: sms and whatsapp reminder issue with seated event (#25294)

* fix: sms reminder issue with seated event

* fix seated event and workflow issue

* fix whatsapp reminder

* Refactor imports in reminderScheduler.ts

* use repository
This commit is contained in:
Anik Dhabal Babu
2025-12-03 04:12:38 +00:00
committed by GitHub
parent 7a66add217
commit a2185d9ee0
6 changed files with 108 additions and 31 deletions
@@ -107,12 +107,14 @@ const handleSeats = async (newSeatedBookingObject: NewSeatedBookingObject) => {
...(typeof resultBooking.metadata === "object" && resultBooking.metadata),
...reqBodyMetadata,
};
// For seated events, use the phone number from the specific attendee being added
const attendeePhoneNumber = invitee[0]?.phoneNumber || smsReminderNumber || null;
try {
const creditService = new CreditService();
await WorkflowService.scheduleWorkflowsForNewBooking({
workflows: workflows,
smsReminderNumber: smsReminderNumber || null,
smsReminderNumber: attendeePhoneNumber,
calendarEvent: {
...evt,
uid: seatedBooking.uid,
@@ -154,7 +156,7 @@ const handleSeats = async (newSeatedBookingObject: NewSeatedBookingObject) => {
metadata,
eventTypeId,
status: "ACCEPTED",
smsReminderNumber: seatedBooking?.smsReminderNumber || undefined,
smsReminderNumber: attendeePhoneNumber || undefined,
rescheduledBy,
};
@@ -17,4 +17,26 @@ export class BookingSeatRepository {
},
});
}
getByReferenceUidWithAttendeeDetails(referenceUid: string) {
return this.prismaClient.bookingSeat.findUnique({
where: {
referenceUid,
},
select: {
attendee: {
select: {
name: true,
id: true,
bookingId: true,
noShow: true,
phoneNumber: true,
email: true,
locale: true,
timeZone: true,
},
},
},
});
}
}
@@ -5,6 +5,7 @@ import { NextResponse } from "next/server";
import dayjs from "@calcom/dayjs";
import { bulkShortenLinks } from "@calcom/ee/workflows/lib/reminders/utils";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import { BookingSeatRepository } from "@calcom/features/bookings/repositories/BookingSeatRepository";
import { CreditService } from "@calcom/features/ee/billing/credit-service";
import { getBookerBaseUrl } from "@calcom/features/ee/organizations/lib/getBookerUrlServer";
import { isAttendeeAction } from "@calcom/features/ee/workflows/lib/actionHelperFunctions";
@@ -61,24 +62,34 @@ export async function handler(req: NextRequest) {
const teamId = reminder.workflowStep.workflow.teamId;
try {
// For seated events, get the correct attendee based on seatReferenceId
let targetAttendee = reminder.booking?.attendees[0];
if (reminder.seatReferenceId) {
const bookingSeatRepository = new BookingSeatRepository(prisma);
const seatAttendeeData = await bookingSeatRepository.getByReferenceUidWithAttendeeDetails(
reminder.seatReferenceId
);
if (seatAttendeeData?.attendee) {
targetAttendee = seatAttendeeData.attendee;
}
}
const sendTo =
reminder.workflowStep.action === WorkflowActions.SMS_NUMBER
? reminder.workflowStep.sendTo
: reminder.booking?.smsReminderNumber;
: targetAttendee?.phoneNumber;
const userName =
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE
? reminder.booking?.attendees[0].name
: "";
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE ? targetAttendee?.name || "" : "";
const attendeeName =
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE
? reminder.booking?.user?.name
: reminder.booking?.attendees[0].name;
: targetAttendee?.name;
const timeZone =
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE
? reminder.booking?.attendees[0].timeZone
? targetAttendee?.timeZone
: reminder.booking?.user?.timeZone;
const senderID = getSenderId(sendTo, reminder.workflowStep.sender);
@@ -86,7 +97,7 @@ export async function handler(req: NextRequest) {
const locale =
reminder.workflowStep.action === WorkflowActions.EMAIL_ATTENDEE ||
reminder.workflowStep.action === WorkflowActions.SMS_ATTENDEE
? reminder.booking?.attendees[0].locale
? targetAttendee?.locale
: reminder.booking?.user?.locale;
let message: string | null = reminder.workflowStep.reminderBody || null;
@@ -111,7 +122,7 @@ export async function handler(req: NextRequest) {
const recipientEmail = getWorkflowRecipientEmail({
action: reminder.workflowStep.action || WorkflowActions.SMS_NUMBER,
attendeeEmail: reminder.booking.attendees[0].email,
attendeeEmail: targetAttendee?.email,
organizerEmail: reminder.booking.user?.email,
});
@@ -131,8 +142,8 @@ export async function handler(req: NextRequest) {
const variables: VariablesType = {
eventName: reminder.booking?.eventType?.title,
organizerName: reminder.booking?.user?.name || "",
attendeeName: reminder.booking?.attendees[0].name,
attendeeEmail: reminder.booking?.attendees[0].email,
attendeeName: targetAttendee?.name,
attendeeEmail: targetAttendee?.email,
eventDate: dayjs(reminder.booking?.startTime).tz(timeZone),
eventEndTime: dayjs(reminder.booking?.endTime).tz(timeZone),
timeZone: timeZone,
@@ -142,13 +153,9 @@ export async function handler(req: NextRequest) {
meetingUrl,
cancelLink,
rescheduleLink,
attendeeTimezone: reminder.booking.attendees[0].timeZone,
eventTimeInAttendeeTimezone: dayjs(reminder.booking.startTime).tz(
reminder.booking.attendees[0].timeZone
),
eventEndTimeInAttendeeTimezone: dayjs(reminder.booking?.endTime).tz(
reminder.booking.attendees[0].timeZone
),
attendeeTimezone: targetAttendee?.timeZone,
eventTimeInAttendeeTimezone: dayjs(reminder.booking.startTime).tz(targetAttendee?.timeZone),
eventEndTimeInAttendeeTimezone: dayjs(reminder.booking?.endTime).tz(targetAttendee?.timeZone),
};
const customMessage = customTemplate(
reminder.workflowStep.reminderBody || "",
@@ -190,7 +197,7 @@ export async function handler(req: NextRequest) {
fallbackData:
reminder.workflowStep.action && isAttendeeAction(reminder.workflowStep.action)
? {
email: reminder.booking.attendees[0].email,
email: targetAttendee?.email,
t: await getTranslation(locale || "en", "common"),
replyTo: reminder.booking?.user?.email ?? "",
workflowStepId: reminder.workflowStep.id,
@@ -3,6 +3,7 @@ import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import dayjs from "@calcom/dayjs";
import { BookingSeatRepository } from "@calcom/features/bookings/repositories/BookingSeatRepository";
import { CreditService } from "@calcom/features/ee/billing/credit-service";
import { getTranslation } from "@calcom/lib/server/i18n";
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
@@ -53,24 +54,34 @@ export async function handler(req: NextRequest) {
const teamId = reminder.workflowStep.workflow.teamId;
try {
// For seated events, get the correct attendee based on seatReferenceId
let targetAttendee = reminder.booking?.attendees[0];
if (reminder.seatReferenceId) {
const bookingSeatRepository = new BookingSeatRepository(prisma);
const seatAttendeeData = await bookingSeatRepository.getByReferenceUidWithAttendeeDetails(
reminder.seatReferenceId
);
if (seatAttendeeData?.attendee) {
targetAttendee = seatAttendeeData.attendee;
}
}
const sendTo =
reminder.workflowStep.action === WorkflowActions.WHATSAPP_NUMBER
? reminder.workflowStep.sendTo
: reminder.booking?.smsReminderNumber;
: targetAttendee?.phoneNumber;
const userName =
reminder.workflowStep.action === WorkflowActions.WHATSAPP_ATTENDEE
? reminder.booking?.attendees[0].name
: "";
reminder.workflowStep.action === WorkflowActions.WHATSAPP_ATTENDEE ? targetAttendee?.name || "" : "";
const attendeeName =
reminder.workflowStep.action === WorkflowActions.WHATSAPP_ATTENDEE
? reminder.booking?.user?.name
: reminder.booking?.attendees[0].name;
: targetAttendee?.name;
const timeZone =
reminder.workflowStep.action === WorkflowActions.WHATSAPP_ATTENDEE
? reminder.booking?.attendees[0].timeZone
? targetAttendee?.timeZone
: reminder.booking?.user?.timeZone;
const startTime = reminder.booking?.startTime.toISOString();
@@ -121,8 +132,8 @@ export async function handler(req: NextRequest) {
fallbackData:
reminder.workflowStep.action && isAttendeeAction(reminder.workflowStep.action)
? {
email: reminder.booking.attendees[0].email,
t: await getTranslation(reminder.booking.attendees[0].locale || "en", "common"),
email: targetAttendee?.email,
t: await getTranslation(targetAttendee?.locale || "en", "common"),
replyTo: reminder.booking?.user?.email ?? "",
workflowStepId: reminder.workflowStep.id,
}
@@ -49,7 +49,7 @@ type PartialBooking =
export type PartialWorkflowReminder = Pick<
WorkflowReminder,
"id" | "isMandatoryReminder" | "scheduledDate" | "uuid"
"id" | "isMandatoryReminder" | "scheduledDate" | "uuid" | "seatReferenceId"
> & {
booking: PartialBooking | null;
} & { workflowStep: PartialWorkflowStep };
@@ -134,6 +134,7 @@ export const select = {
scheduledDate: true,
isMandatoryReminder: true,
uuid: true,
seatReferenceId: true,
workflowStep: {
select: {
action: true,
@@ -63,6 +63,30 @@ export type ScheduleWorkflowRemindersArgs = ProcessWorkflowStepParams & {
creditCheckFn: CreditCheckFn;
};
const getReminderPhoneNumber = async (
action: WorkflowActions,
seatReferenceUid: string | undefined,
smsReminderNumber: string | null,
stepSendTo: string | null
) => {
const isAttendeeAction =
action === WorkflowActions.SMS_ATTENDEE || action === WorkflowActions.WHATSAPP_ATTENDEE;
if (!isAttendeeAction) {
return stepSendTo;
}
if (seatReferenceUid) {
const bookingSeatRepository = new BookingSeatRepository(prisma);
const seatAttendeeData = await bookingSeatRepository.getByReferenceUidWithAttendeeDetails(
seatReferenceUid
);
return seatAttendeeData?.attendee?.phoneNumber || smsReminderNumber;
}
return smsReminderNumber;
};
const processWorkflowStep = async (
workflow: Workflow,
step: WorkflowStep,
@@ -101,7 +125,12 @@ const processWorkflowStep = async (
if (isSMSAction(step.action)) {
const { scheduleSMSReminder } = await import("./smsReminderManager");
const sendTo = step.action === WorkflowActions.SMS_ATTENDEE ? smsReminderNumber : step.sendTo;
const sendTo = await getReminderPhoneNumber(
step.action,
seatReferenceUid,
smsReminderNumber,
step.sendTo
);
await scheduleSMSReminder({
...scheduleFunctionParams,
@@ -139,7 +168,12 @@ const processWorkflowStep = async (
}
const { scheduleWhatsappReminder } = await import("./whatsappReminderManager");
const sendTo = step.action === WorkflowActions.WHATSAPP_ATTENDEE ? smsReminderNumber : step.sendTo;
const sendTo = await getReminderPhoneNumber(
step.action,
seatReferenceUid,
smsReminderNumber,
step.sendTo
);
await scheduleWhatsappReminder({
...scheduleFunctionParams,