$data */ public function createSeries(User $user, Organization $organization, array $data): Room { $seriesId = (string) Str::uuid(); $room = $this->rooms->createScheduled($user, $organization, array_merge($data, [ 'recurring_series_id' => $seriesId, 'recurrence_rule' => $data['recurrence_rule'], 'recurrence_interval' => $data['recurrence_interval'] ?? 1, 'recurrence_until' => $data['recurrence_until'] ?? null, ])); $this->spawnNextOccurrences($room, 5); return $room; } public function spawnNextOccurrences(Room $parent, int $count = 1): void { if (! $parent->isRecurring()) { return; } $last = Room::where('recurring_series_id', $parent->recurring_series_id) ->orderByDesc('scheduled_at') ->first(); $cursor = Carbon::parse($last?->scheduled_at ?? $parent->scheduled_at); for ($i = 0; $i < $count; $i++) { $cursor = $this->nextOccurrence($cursor, $parent->recurrence_rule, (int) $parent->recurrence_interval); if ($parent->recurrence_until && $cursor->toDateString() > $parent->recurrence_until) { break; } if (Room::where('recurring_series_id', $parent->recurring_series_id) ->whereDate('scheduled_at', $cursor->toDateString()) ->exists()) { continue; } Room::create([ 'owner_ref' => $parent->owner_ref, 'organization_id' => $parent->organization_id, 'branch_id' => $parent->branch_id, 'host_user_ref' => $parent->host_user_ref, 'title' => $parent->title, 'description' => $parent->description, 'type' => 'scheduled', 'status' => 'scheduled', 'scheduled_at' => $cursor, 'duration_minutes' => $parent->duration_minutes, 'timezone' => $parent->timezone, 'passcode' => $parent->passcode, 'settings' => $parent->settings, 'recurring_series_id' => $parent->recurring_series_id, 'recurrence_rule' => $parent->recurrence_rule, 'recurrence_interval' => $parent->recurrence_interval, 'recurrence_until' => $parent->recurrence_until, ]); } } protected function nextOccurrence(Carbon $from, string $rule, int $interval): Carbon { return match ($rule) { 'daily' => $from->copy()->addDays($interval), 'weekly' => $from->copy()->addWeeks($interval), 'monthly' => $from->copy()->addMonths($interval), default => $from->copy()->addWeeks($interval), }; } }