'datetime', 'end_datetime' => 'datetime', 'is_all_day' => 'boolean', 'capacity' => 'integer', 'available_tickets' => 'integer', 'price' => 'decimal:2', 'created_at' => 'datetime', 'updated_at' => 'datetime', ]; /** * Ein EventOccurrence gehört zu einem Event. */ public function event(): BelongsTo { return $this->belongsTo(Event::class); } /** * Scope für geplante Vorkommen ab heute. */ public function scopeUpcoming($query) { return $query->where('start_datetime', '>=', now()) ->where('status', 'scheduled') ->orderBy('start_datetime'); } /** * Scope für Vorkommen an einem bestimmten Datum. */ public function scopeOnDate($query, $date) { return $query->whereDate('start_datetime', $date); } /** * Scope für Vorkommen in einem Zeitraum. */ public function scopeBetween($query, $startDate, $endDate) { return $query->whereBetween('start_datetime', [$startDate, $endDate]); } /** * Scope für geplante Vorkommen. */ public function scopeScheduled($query) { return $query->where('status', 'scheduled'); } /** * Prüfe ob Tickets verfügbar sind. */ public function hasAvailableTickets() { if ($this->capacity === null) { return true; // Unbegrenzte Kapazität } return $this->available_tickets > 0; } /** * Formatierte Dauer (z.B. "14:00 - 16:00" oder "ganztägig") */ public function getFormattedDurationAttribute() { if ($this->is_all_day) { return 'Ganztägig'; } $start = $this->start_datetime->format('H:i'); $end = $this->end_datetime?->format('H:i') ?? '∞'; return "{$start} - {$end}"; } }