fix: rescheduling last active booking#23601
Conversation
|
@hemantmm is attempting to deploy a commit to the cal Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThe PR reworks how booker active-booking limits are enforced. If Possibly related PRs
Pre-merge checks (5 passed)✅ Passed checks (5 passed)
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Flag potential breaking changes that are not documented:
1. Identify changes to public APIs/exports, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints (including removed/renamed items and changes to types, required params, return values, defaults, or behavior).
2. Ignore purely internal/private changes (e.g., code not exported from package entry points or marked internal).
3. Verify documentation exists: a "Breaking Change" section in the PR description and updates to CHANGELOG.md.Please share your feedback with us on this Discord post. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
🧠 Learnings (1)
📚 Learning: 2025-08-22T16:38:00.225Z
Learnt from: bandhan-majumder
PR: calcom/cal.com#23192
File: packages/lib/server/service/InsightsBookingBaseService.ts:814-816
Timestamp: 2025-08-22T16:38:00.225Z
Learning: In the InsightsBookingBaseService (packages/lib/server/service/InsightsBookingBaseService.ts), when filtering for "accepted" bookings in getMembersStatsWithCount(), using `endTime <= now()` in the SQL condition should be avoided as it conflicts with existing date filtering logic. The components already handle completion filtering by setting `endDate: currentTime` in their query parameters, making additional SQL-level endTime filtering unnecessary and potentially problematic.
Applied to files:
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Install dependencies / Yarn install & cache
| if (offerToRescheduleLastBooking) { | ||
| await checkActiveBookingsLimitAndOfferReschedule({ | ||
| const lastActiveBooking = await prisma.booking.findFirst({ | ||
| where: { | ||
| eventTypeId, | ||
| status: { in: [BookingStatus.ACCEPTED, BookingStatus.PENDING] }, | ||
| attendees: { | ||
| some: { | ||
| email: bookerEmail, | ||
| }, | ||
| }, | ||
| }, | ||
| orderBy: { startTime: "desc" }, | ||
| }); | ||
|
|
||
| if (lastActiveBooking) { | ||
| await prisma.booking.update({ | ||
| where: { id: lastActiveBooking.id }, | ||
| data: { | ||
| status: BookingStatus.CANCELLED, | ||
| rescheduled: true, | ||
| }, | ||
| }); | ||
| } | ||
|
|
||
| return await checkActiveBookingsLimitAndOfferReschedule({ |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Don’t preemptively cancel bookings; gate by limit, align filters to “active”, and avoid canceling PENDING/past meetings.
As written, any time offerToRescheduleLastBooking is true you cancel the most recent booking—even if the booker is under the limit. You also:
- include
PENDINGin the cancel set, while the limit checks only considerACCEPTED→ inconsistent and potentially destructive - don’t restrict by
startTime >= now, so you may cancel a past booking - cancel before the new booking is created, risking data loss if the subsequent flow fails
- fetch full rows instead of a minimal
select
Refactor to:
- only cancel when at/over
maxActiveBookingsPerBooker - cancel only future
ACCEPTEDbookings - minimize data fetched
- drop redundant
return await
Apply this diff:
- const lastActiveBooking = await prisma.booking.findFirst({
- where: {
- eventTypeId,
- status: { in: [BookingStatus.ACCEPTED, BookingStatus.PENDING] },
- attendees: {
- some: {
- email: bookerEmail,
- },
- },
- },
- orderBy: { startTime: "desc" },
- });
-
- if (lastActiveBooking) {
- await prisma.booking.update({
- where: { id: lastActiveBooking.id },
- data: {
- status: BookingStatus.CANCELLED,
- rescheduled: true,
- },
- });
- }
-
- return await checkActiveBookingsLimitAndOfferReschedule({
+ // Cancel only when at/over limit; restrict to future ACCEPTED bookings.
+ const activeAcceptedCount = await prisma.booking.count({
+ where: {
+ eventTypeId,
+ startTime: { gte: new Date() },
+ status: BookingStatus.ACCEPTED,
+ attendees: { some: { email: bookerEmail } },
+ },
+ });
+
+ if (activeAcceptedCount >= maxActiveBookingsPerBooker) {
+ const lastActiveBooking = await prisma.booking.findFirst({
+ where: {
+ eventTypeId,
+ startTime: { gte: new Date() },
+ status: BookingStatus.ACCEPTED,
+ attendees: { some: { email: bookerEmail } },
+ },
+ orderBy: { startTime: "desc" },
+ select: { id: true },
+ });
+
+ if (lastActiveBooking) {
+ await prisma.booking.updateMany({
+ where: { id: lastActiveBooking.id, status: BookingStatus.ACCEPTED },
+ data: { status: BookingStatus.CANCELLED, rescheduled: true },
+ });
+ }
+ }
+
+ return checkActiveBookingsLimitAndOfferReschedule({
eventTypeId,
maxActiveBookingsPerBooker,
bookerEmail,
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (offerToRescheduleLastBooking) { | |
| await checkActiveBookingsLimitAndOfferReschedule({ | |
| const lastActiveBooking = await prisma.booking.findFirst({ | |
| where: { | |
| eventTypeId, | |
| status: { in: [BookingStatus.ACCEPTED, BookingStatus.PENDING] }, | |
| attendees: { | |
| some: { | |
| email: bookerEmail, | |
| }, | |
| }, | |
| }, | |
| orderBy: { startTime: "desc" }, | |
| }); | |
| if (lastActiveBooking) { | |
| await prisma.booking.update({ | |
| where: { id: lastActiveBooking.id }, | |
| data: { | |
| status: BookingStatus.CANCELLED, | |
| rescheduled: true, | |
| }, | |
| }); | |
| } | |
| return await checkActiveBookingsLimitAndOfferReschedule({ | |
| if (offerToRescheduleLastBooking) { | |
| // Cancel only when at/over limit; restrict to future ACCEPTED bookings. | |
| const activeAcceptedCount = await prisma.booking.count({ | |
| where: { | |
| eventTypeId, | |
| startTime: { gte: new Date() }, | |
| status: BookingStatus.ACCEPTED, | |
| attendees: { some: { email: bookerEmail } }, | |
| }, | |
| }); | |
| if (activeAcceptedCount >= maxActiveBookingsPerBooker) { | |
| const lastActiveBooking = await prisma.booking.findFirst({ | |
| where: { | |
| eventTypeId, | |
| startTime: { gte: new Date() }, | |
| status: BookingStatus.ACCEPTED, | |
| attendees: { some: { email: bookerEmail } }, | |
| }, | |
| orderBy: { startTime: "desc" }, | |
| select: { id: true }, | |
| }); | |
| if (lastActiveBooking) { | |
| await prisma.booking.updateMany({ | |
| where: { id: lastActiveBooking.id, status: BookingStatus.ACCEPTED }, | |
| data: { status: BookingStatus.CANCELLED, rescheduled: true }, | |
| }); | |
| } | |
| } | |
| return checkActiveBookingsLimitAndOfferReschedule({ | |
| eventTypeId, | |
| maxActiveBookingsPerBooker, | |
| bookerEmail, | |
| }); | |
| } |
🤖 Prompt for AI Agents
In
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
around lines 24-48, remove the preemptive cancellation and instead: first call
the existing checkActiveBookingsLimitAndOfferReschedule logic to determine if
the booker is at/over the limit; only when that check indicates we must
reschedule, query for the last active booking using filters status = ACCEPTED
and startTime >= now, selecting only the id; then perform the update to mark it
CANCELLED/rescheduled; ensure we do not include PENDING or past meetings in the
cancel query and avoid using redundant "return await".
| if (lastActiveBooking) { | ||
| await prisma.booking.update({ | ||
| where: { id: lastActiveBooking.id }, | ||
| data: { | ||
| status: BookingStatus.CANCELLED, | ||
| rescheduled: true, | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Avoid bypassing cancellation side‑effects; use the booking cancellation/reschedule service with hooks.
Direct prisma.booking.update skips notifications, calendar sync, webhooks, refunds, etc. Route cancellation through the existing domain service (e.g., a “cancelBooking/reschedule” service) or emit the same hooks that normal cancellations do. Ideally, perform “cancel old + create new” in one orchestrated path/transaction.
Run this to locate the canonical cancellation/reschedule utilities to call instead of raw updates:
🏁 Script executed:
#!/bin/bash
# Find booking cancellation/reschedule helpers/services
rg -nP -C3 '(cancelBooking|CancelBooking|bookingCancel|reschedul(e|ed|ing).*(service|handler)|Booking.*cancel)' --type=ts --type=tsxLength of output: 162
🏁 Script executed:
#!/bin/bash
# Re-run search for booking cancellation/reschedule utilities in TS/TSX files using globs
rg -nP -C3 '(cancelBooking|CancelBooking|bookingCancel|reschedul(e|ed|ing).*(service|handler)|Booking.*cancel)' -g '*.ts' -g '*.tsx'Length of output: 142389
Use the domain-level cancellation service, not prisma.booking.update.
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts:38–46 – direct updates bypass all of your cancellation side-effects (webhooks, notifications, calendar sync, refunds, etc.). Import and invoke the canonical handler (e.g. handleCancelBooking from @calcom/features/bookings/lib/handleCancelBooking) so “cancel old + create new” runs in one orchestrated path.
kart1ka
left a comment
There was a problem hiding this comment.
This is not the solution we are looking for. You are just rescheduling the existing booking without informing the user about it. Also what happens if there are more than one existing bookings?
anikdhabal
left a comment
There was a problem hiding this comment.
Agree with @kart1ka here, also the issue is related to reschedule not normal booking
…/cal.com into reschedule-last-booking
@kart1ka, I have updated the fix. You can have a look at the video above. |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx (1)
160-173: Localize the button label inside ServerTrans.Direct English text violates our TSX i18n guideline. Use t() for the label so it can be translated.
- <button + <button key="please-select-a-new-time-button" type="button" className="underline" onClick={onCancel}> - Please select a new time + {t("please_select_a_new_time")} </button>,
♻️ Duplicate comments (1)
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts (1)
39-42: Do not bypass domain cancellation side-effects; guard against races.Direct prisma.booking.update skips notifications, calendar sync, webhooks, refunds, etc., and is racy between read and write. Route through the canonical cancellation/reschedule service (e.g., handleCancelBooking/booking cancellation domain handler) or at minimum add status/time guards and use updateMany.
- await prisma.booking.update({ - where: { id: bookingToReschedule.id }, - data: { status: BookingStatus.CANCELLED, rescheduled: true }, - }); + // Prefer: call the domain-level cancellation/reschedule service here. + // Fallback hardening: + await prisma.booking.updateMany({ + where: { + id: bookingToReschedule.id, + status: BookingStatus.ACCEPTED, + startTime: { gte: now }, + }, + data: { status: BookingStatus.CANCELLED, rescheduled: true }, + });
🧹 Nitpick comments (5)
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts (3)
1-1: Remove unnecessary ESLint disable.No unused vars in this file; keep the rule active.
-/* eslint-disable @typescript-eslint/no-unused-vars */
44-51: Avoid coupling UI to literal message strings; rely on code + data.The UI already keys off ErrorCode.BookerLimitExceededReschedule. Keep message generic and let translations derive text; keep previousDate/rescheduleUid in data.
- throw new ErrorWithCode( - ErrorCode.BookerLimitExceededReschedule, - "Previous booking has been rescheduled", - { - previousDate: bookingToReschedule.startTime.toISOString(), - rescheduleUid: bookingToReschedule.uid, - } - ); + throw new ErrorWithCode(ErrorCode.BookerLimitExceededReschedule, "booker_limit_exceeded_reschedule", { + previousDate: bookingToReschedule.startTime.toISOString(), + rescheduleUid: bookingToReschedule.uid, + });
68-79: Unify “active” filters and simplify status condition.Use the same where-clause as above (future + ACCEPTED) for consistency; replace in: [ACCEPTED] with equality; also consider extracting the filter to a shared helper to avoid drift.
- startTime: { gte: new Date() }, - status: { in: [BookingStatus.ACCEPTED] }, + startTime: { gte: new Date() }, + status: BookingStatus.ACCEPTED, attendees: { some: { email: bookerEmail } },packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx (2)
314-329: Key off error.code only; don’t match literal messages.String comparisons are brittle and break i18n. The server already sends ErrorCode.BookerLimitExceededReschedule with data.previousDate; rely on that.
- if ( - error?.code === ErrorCode.BookerLimitExceededReschedule || - error?.message === "Previous booking has been rescheduled" - ) { + if (error?.code === ErrorCode.BookerLimitExceededReschedule) {
331-335: Avoid t(error.message) for arbitrary server strings; map known codes to keys.If message isn’t an i18n key, t() won’t translate it. Prefer a small map from server ErrorCode → translation key, with a safe fallback.
- {responseVercelIdHeader ?? ""} {t(error.message)} + {responseVercelIdHeader ?? ""} {t(error.code ?? "can_you_try_again")}Or introduce a helper:
const errorKeyByCode: Record<string, string> = { [ErrorCode.BookerLimitExceeded]: "maximum_booking_limit_reached", [ErrorCode.BookerLimitExceededReschedule]: "your_previous_booking_has_been_rescheduled", };
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx(7 hunks)packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts(3 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Always use
t()for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsxpackages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsxpackages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
🧠 Learnings (4)
📚 Learning: 2025-08-27T13:32:46.887Z
Learnt from: supalarry
PR: calcom/cal.com#23364
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/transformers/internal-to-api/internal-to-api.spec.ts:295-296
Timestamp: 2025-08-27T13:32:46.887Z
Learning: In calcom/cal.com, when transforming booking fields from internal to API format, tests in organizations-event-types.e2e-spec.ts already expect name field label and placeholder to be empty strings ("") rather than undefined. PR changes that set these to explicit empty strings are typically fixing implementation to match existing test expectations rather than breaking changes.
Applied to files:
packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx
📚 Learning: 2025-07-15T12:59:34.389Z
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
Applied to files:
packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx
📚 Learning: 2025-08-22T16:38:00.225Z
Learnt from: bandhan-majumder
PR: calcom/cal.com#23192
File: packages/lib/server/service/InsightsBookingBaseService.ts:814-816
Timestamp: 2025-08-22T16:38:00.225Z
Learning: In the InsightsBookingBaseService (packages/lib/server/service/InsightsBookingBaseService.ts), when filtering for "accepted" bookings in getMembersStatsWithCount(), using `endTime <= now()` in the SQL condition should be avoided as it conflicts with existing date filtering logic. The components already handle completion filtering by setting `endDate: currentTime` in their query parameters, making additional SQL-level endTime filtering unnecessary and potentially problematic.
Applied to files:
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
📚 Learning: 2025-08-27T12:15:43.830Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts:41-44
Timestamp: 2025-08-27T12:15:43.830Z
Learning: In calcom/cal.com, the AgentService.getAgent() method in packages/features/calAIPhone/providers/retellAI/services/AgentService.ts does NOT include authorization checks - it only validates the agentId parameter and directly calls the repository without verifying user/team access. This contrasts with other methods like getAgentWithDetails() which properly use findByIdWithUserAccessAndDetails() for authorization. When reviewing updateToolsFromAgentId() calls, always verify both agent ownership and eventType ownership are checked.
Applied to files:
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Linters / lint
- GitHub Check: Tests / Unit
- GitHub Check: Type check / check-types
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (4)
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts (3)
21-22: Early return looks good.Avoids unnecessary DB calls when limit is disabled.
32-38: Confirm selection of booking index to reschedule.You select activeBookings[maxActiveBookingsPerBooker - 1] in a list ordered by startTime desc. This targets the Nth-most-recent future booking, not necessarily the “last created” or “oldest future” booking. Please confirm product spec; otherwise we may need earliest future (asc + first) or most recent (desc + first).
58-80: Remove or exportcheckActiveBookingsLimit
No call sites found across.ts/.tsxfiles—delete this dead helper or, if it’s meant to be used elsewhere, export it and add corresponding tests.packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx (1)
243-257: UX change: confirm CTA hidden when multiple active bookings.Hiding the confirm button blocks progression from this screen. Confirm this matches expected flow (e.g., user must first resolve bookings list), or provide a dedicated “Go to last booking”/“Manage bookings” action.
packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx
Show resolved
Hide resolved
| const activeBookings = await prisma.booking.findMany({ | ||
| where: { | ||
| eventTypeId, | ||
| status: { in: [BookingStatus.ACCEPTED, BookingStatus.PENDING] }, | ||
| attendees: { some: { email: bookerEmail } }, | ||
| }, | ||
| orderBy: { startTime: "desc" }, | ||
| }); | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Scope the Prisma query to “active” future ACCEPTED bookings and fetch only needed fields.
Current query:
- includes PENDING and past bookings (inconsistent with checkActiveBookingsLimit below)
- fetches entire rows
- scans all matches
Refactor to align filters, reduce IO, and cap results at the limit.
- const activeBookings = await prisma.booking.findMany({
- where: {
- eventTypeId,
- status: { in: [BookingStatus.ACCEPTED, BookingStatus.PENDING] },
- attendees: { some: { email: bookerEmail } },
- },
- orderBy: { startTime: "desc" },
- });
+ const now = new Date();
+ const activeBookings = await prisma.booking.findMany({
+ where: {
+ eventTypeId,
+ startTime: { gte: now },
+ status: BookingStatus.ACCEPTED,
+ attendees: { some: { email: bookerEmail } },
+ },
+ orderBy: { startTime: "desc" },
+ select: { id: true, startTime: true, uid: true },
+ take: maxActiveBookingsPerBooker, // we only need up to the Nth most recent
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const activeBookings = await prisma.booking.findMany({ | |
| where: { | |
| eventTypeId, | |
| status: { in: [BookingStatus.ACCEPTED, BookingStatus.PENDING] }, | |
| attendees: { some: { email: bookerEmail } }, | |
| }, | |
| orderBy: { startTime: "desc" }, | |
| }); | |
| // Only consider future ACCEPTED bookings and fetch minimal fields up to the limit | |
| const now = new Date(); | |
| const activeBookings = await prisma.booking.findMany({ | |
| where: { | |
| eventTypeId, | |
| startTime: { gte: now }, | |
| status: BookingStatus.ACCEPTED, | |
| attendees: { some: { email: bookerEmail } }, | |
| }, | |
| orderBy: { startTime: "desc" }, | |
| select: { id: true, startTime: true, uid: true }, | |
| take: maxActiveBookingsPerBooker, // only need the N most recent | |
| }); |
🤖 Prompt for AI Agents
In
packages/features/bookings/lib/handleNewBooking/checkActiveBookingsLimitForBooker.ts
around lines 23 to 31, the Prisma query currently returns PENDING and past
bookings and selects full rows which contradicts the active-bookings limit
logic; change the where clause to only ACCEPTED bookings with startTime in the
future (e.g., startTime: { gt: new Date() }), restrict the select to only the
minimal fields you need (like id and startTime or just id), add take: limit to
cap results at the configured limit, and keep orderBy as needed (e.g., startTime
desc) so the query is efficient and aligned with the limit check.
|
Thank you for the PR. But closing in favour of #23717. |
closes: #23588
What does this PR do?
Visual Demo (For contributors especially)
A visual demonstration is strongly recommended, for both the original and new change (video / image - any one).
Video Demo (if applicable):
Before:
Screen.Recording.2025-09-04.at.23.55.01.mov
After:
Screen.Recording.2025-09-09.at.10.59.47.mov
Screen.Recording.2025-09-09.at.10.57.07.mov
Mandatory Tasks (DO NOT REMOVE)
How should this be tested?
Checklist