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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user