fix: pass seatUid when rescheduling seated booking from booking limit error (#26389)

* fix: pass seatUid when rescheduling seated booking from booking limit error

Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>

* test: add test case for seatUid in booking limit reschedule error for seated events

Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-01-19 17:30:29 +09:00
1 parent 0aad5520cc
commit 9f0d035a3b
3 files changed
+130 -2

No files matched your search

@@ -399,12 +399,12 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata, isBookin
}
const error = err as Error & {
data: { rescheduleUid: string; startTime: string; attendees: string[] };
data: { rescheduleUid: string; startTime: string; attendees: string[]; seatUid?: string };
traceId?: string;
};
if (error.message === ErrorCode.BookerLimitExceededReschedule && error.data?.rescheduleUid) {
setRescheduleUid(error.data?.rescheduleUid);
setRescheduleUid(error.data?.seatUid ?? error.data?.rescheduleUid);
setBookingData({
uid: error.data?.rescheduleUid,
startTime: error.data?.startTime,
@@ -102,12 +102,22 @@ const checkActiveBookingsLimitAndOfferReschedule = async ({
select: {
name: true,
email: true,
bookingSeat: {
select: {
referenceUid: true,
},
},
},
where: {
email: bookerEmail,
},
},
},
});
const lastBooking = bookingsCount[bookingsCount.length - 1];
// Get the seatUid for the booker's seat in this booking (if it's a seated event)
const seatUid = lastBooking?.attendees[0]?.bookingSeat?.referenceUid;
if (bookingsCount.length >= maxActiveBookingsPerBooker) {
log.warn(`Maximum booking limit reached for ${bookerEmail} for event type ${eventTypeId}`);
@@ -118,6 +128,7 @@ const checkActiveBookingsLimitAndOfferReschedule = async ({
rescheduleUid: lastBooking.uid,
startTime: lastBooking.startTime,
attendees: lastBooking.attendees,
seatUid,
}
);
}
@@ -12,6 +12,7 @@ import {
getScenarioData,
getGoogleCalendarCredential,
mockCalendarToHaveNoBusySlots,
getMockBookingAttendee,
} from "@calcom/testing/lib/bookingScenario/bookingScenario";
import { getMockRequestDataForBooking } from "@calcom/testing/lib/bookingScenario/getMockRequestDataForBooking";
import { setupAndTeardown } from "@calcom/testing/lib/bookingScenario/setupAndTeardown";
@@ -402,6 +403,122 @@ describe("Booking Validation Specifications", () => {
);
}
});
test("includes seatUid in reschedule error for seated events", async () => {
vi.setSystemTime(new Date("2025-01-01"));
const plus1DateString = "2025-01-02";
const plus2DateString = "2025-01-03";
const handleNewBooking = getNewBookingHandler();
const bookerA = getBooker({
email: "bookerA@example.com",
name: "Booker A",
});
const bookerB = getBooker({
email: "bookerB@example.com",
name: "Booker B",
});
const organizer = getOrganizer({
name: "Organizer",
email: "organizer@example.com",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
});
const seatReferenceUidA = "seat-reference-uid-a";
await createBookingScenario(
getScenarioData({
eventTypes: [
{
id: 1,
slotInterval: 30,
length: 30,
maxActiveBookingsPerBooker: 1,
maxActiveBookingPerBookerOfferReschedule: true,
seatsPerTimeSlot: 3,
users: [
{
id: 101,
},
],
},
],
organizer,
apps: [TestData.apps["google-calendar"]],
bookings: [
{
uid: "existing-booking-1",
eventTypeId: 1,
userId: organizer.id,
startTime: `${plus1DateString}T10:00:00.000Z`,
endTime: `${plus1DateString}T10:30:00.000Z`,
title: "Existing Booking",
status: BookingStatus.ACCEPTED,
attendees: [
getMockBookingAttendee({
id: 1,
name: bookerA.name,
email: bookerA.email,
locale: "en",
timeZone: "America/Toronto",
bookingSeat: {
referenceUid: seatReferenceUidA,
data: {},
},
}),
getMockBookingAttendee({
id: 2,
name: bookerB.name,
email: bookerB.email,
locale: "en",
timeZone: "America/Toronto",
bookingSeat: {
referenceUid: "seat-reference-uid-b",
data: {},
},
}),
],
},
],
})
);
await mockCalendarToHaveNoBusySlots("googlecalendar", {});
const mockBookingData = getMockRequestDataForBooking({
data: {
eventTypeId: 1,
start: `${plus2DateString}T10:00:00.000Z`,
end: `${plus2DateString}T10:30:00.000Z`,
responses: {
email: bookerA.email,
name: bookerA.name,
location: { optionValue: "", value: "New York" },
},
},
});
try {
await handleNewBooking({
bookingData: mockBookingData,
});
expect.fail("Expected booking to throw booker_limit_exceeded_error_reschedule");
} catch (error) {
expect(error.message).toEqual("booker_limit_exceeded_error_reschedule");
expect(error.data).toEqual(
expect.objectContaining({
rescheduleUid: "existing-booking-1",
seatUid: seatReferenceUidA,
})
);
}
});
});
describe("User Email Verification Setting", () => {