Skip to content

fix(bookings): thread recurring series id through round-robin recurri…#29767

Open
shafi-VM wants to merge 2 commits into
calcom:mainfrom
shafi-VM:fix/recurring-rr-thirdparty-series-id
Open

fix(bookings): thread recurring series id through round-robin recurri…#29767
shafi-VM wants to merge 2 commits into
calcom:mainfrom
shafi-VM:fix/recurring-rr-thirdparty-series-id

Conversation

@shafi-VM

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes #29766

For round-robin recurring bookings, RecurringBookingService handles the first slot in a pre-loop (to pick the lucky host) but extracted only luckyUsers from its result — not thirdPartyRecurringEventId. The remaining occurrences then started the loop with a null series id and each created their own third-party recurring series (withRecurringEventId(null) → no existingRecurringEvent → the calendar service's events.insert path), orphaning the first occurrence in a separate series. The non-round-robin path already threads the id (it extracts it after each booking). This PR extracts thirdPartyRecurringEventId from the first round-robin slot too, mirroring the main loop, so all occurrences join one series.

Visual Demo (For contributors especially)

Backend logic fix with no UI surface — demonstrated with a red→green unit test rather than a recording (see How should this be tested?).

Video Demo (if applicable):

N/A — no UI change.

Image Demo (if applicable):

N/A — no UI change.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox. — N/A (no developer-facing API or docs change)
  • I confirm automated tests are in place that prove my fix is effective.

How should this be tested?

  • Data: a round-robin event type with recurrence enabled and hosts connected to Google Calendar. Book several recurring occurrences.
  • Expected: all occurrences belong to a single recurring series in the calendar (previously occurrence 0 was orphaned in its own series).
  • Automated: new unit test in RecurringBookingService.test.ts asserts the second booking is invoked with the first slot's thirdPartyRecurringEventId — verified red (null) before the fix, green after; the existing recurring integration test in the same file still passes.

Checklist

  • N/A — follows the contributing guide and style guidelines, tests included, PR is small (2 files, ~58 lines).

…ng slots

In RecurringBookingService, the round-robin pre-loop creates the first recurring slot but extracted only luckyUsers from the result, not thirdPartyRecurringEventId. The remaining slots then started the loop with a null id and each created their own third-party recurring series (via withRecurringEventId -> existingRecurringEvent -> the calendar service's insert path), orphaning the first occurrence in a separate series. The non-round-robin path already threads the id by extracting it after each booking.

Extract thirdPartyRecurringEventId from the first round-robin slot's references too, mirroring the loop below, so all occurrences join one series. Adds a unit regression test.
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Cal.diy, @shafi-VM! Thanks for opening this pull request.

A few things to keep in mind:

  • This is Cal.diy, not Cal.com. Cal.diy is a community-driven, fully open-source fork of Cal.com licensed under MIT. Your changes here will be part of Cal.diy — they will not be deployed to the Cal.com production app.
  • Please review our Contributing Guidelines if you haven't already.
  • Make sure your PR title follows the Conventional Commits format.

A maintainer will review your PR soon. Thanks for contributing!

@github-actions github-actions Bot added the 🐛 bug Something isn't working label Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b73751ee-a0ff-43d5-b698-55349bed0cc2

📥 Commits

Reviewing files that changed from the base of the PR and between 6c4a236 and f34c401.

📒 Files selected for processing (1)
  • packages/features/bookings/lib/service/RecurringBookingService.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/features/bookings/lib/service/RecurringBookingService.ts

📝 Walkthrough

Walkthrough

Updated RecurringBookingService to extract the third-party recurring event ID from the first round-robin booking and pass it to later slots. Added Vitest coverage that mocks booking creation and verifies the ID is reused on the second booking.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main fix: threading the recurring series id through round-robin recurring bookings.
Description check ✅ Passed The description is clearly related and accurately describes the bug fix and added regression test.
Linked Issues check ✅ Passed The changes satisfy #29766 by propagating thirdPartyRecurringEventId for round-robin recurring bookings and adding coverage.
Out of Scope Changes check ✅ Passed The PR stays within scope, touching only the booking service fix and its regression test.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/features/bookings/lib/service/RecurringBookingService.ts (1)

72-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Logic is correct; consider extracting the duplicated reference-extraction pattern.

The new block at lines 75-82 duplicates the same thirdPartyRecurringEventId extraction logic already present at lines 130-138. Extracting a small helper would eliminate the duplication and keep both call sites in sync.

♻️ Optional: extract a shared helper
+function extractThirdPartyRecurringEventId(
+  references: { thirdPartyRecurringEventId?: string | null }[] | undefined
+): string | null {
+  if (references && references.length > 0) {
+    for (const reference of references) {
+      if (reference.thirdPartyRecurringEventId) {
+        return reference.thirdPartyRecurringEventId;
+      }
+    }
+  }
+  return null;
+}
+
 // ... in the round-robin block:
-    if (!thirdPartyRecurringEventId && firstBookingResult.references && firstBookingResult.references.length > 0) {
-      for (const reference of firstBookingResult.references) {
-        if (reference.thirdPartyRecurringEventId) {
-          thirdPartyRecurringEventId = reference.thirdPartyRecurringEventId;
-          break;
-        }
-      }
-    }
+    if (!thirdPartyRecurringEventId) {
+      thirdPartyRecurringEventId = extractThirdPartyRecurringEventId(firstBookingResult.references) ?? thirdPartyRecurringEventId;
+    }

And similarly for the loop at lines 130-138.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/features/bookings/lib/service/RecurringBookingService.ts` around
lines 72 - 82, Extract the repeated thirdPartyRecurringEventId lookup from the
firstBookingResult block and the later recurring-booking loop into a shared
helper, then replace both inline loops with calls to that helper while
preserving the existing fallback behavior and first-match selection.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/features/bookings/lib/service/RecurringBookingService.ts`:
- Around line 72-82: Extract the repeated thirdPartyRecurringEventId lookup from
the firstBookingResult block and the later recurring-booking loop into a shared
helper, then replace both inline loops with calls to that helper while
preserving the existing fallback behavior and first-match selection.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f29bd3a2-ebd1-431c-9acc-0fda7a10e5b9

📥 Commits

Reviewing files that changed from the base of the PR and between f004349 and 6c4a236.

📒 Files selected for processing (2)
  • packages/features/bookings/lib/service/RecurringBookingService.test.ts
  • packages/features/bookings/lib/service/RecurringBookingService.ts

Address CodeRabbit nitpick on calcom#29767: dedupe the thirdPartyRecurringEventId extraction used by the round-robin pre-loop and the main loop into a shared helper, so both sites stay in sync — their divergence was the root cause of the bug. Also types the accumulator as string | null.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 bug Something isn't working size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug]: round-robin recurring bookings create a split third-party calendar series

1 participant