'boolean', 'group_ferienwohnungen' => 'boolean', 'subscribed_at' => 'datetime', 'unsubscribed_at' => 'datetime', 'last_booking_at' => 'datetime', 'last_travel_end_date' => 'datetime', 'last_synced_at' => 'datetime', 'total_bookings_kulturreisen' => 'int', 'total_bookings_ferienwohnungen' => 'int', 'customer_id' => 'int', 'travel_user_id' => 'int', ]; protected $fillable = [ 'email', 'firstname', 'lastname', 'group_kulturreisen', 'group_ferienwohnungen', 'source', 'status', 'subscribed_at', 'unsubscribed_at', 'last_booking_at', 'last_travel_end_date', 'total_bookings_kulturreisen', 'total_bookings_ferienwohnungen', 'customer_id', 'travel_user_id', 'last_synced_at', 'sync_hash', 'notes', ]; // Konstanten für Source const SOURCE_BOOKING_KULTURREISEN = 'booking_kulturreisen'; const SOURCE_BOOKING_FERIENWOHNUNGEN = 'booking_ferienwohnungen'; const SOURCE_NEWSLETTER_SIGNUP = 'newsletter_signup'; const SOURCE_MANUAL = 'manual'; const SOURCE_IMPORT = 'import'; // Konstanten für Status const STATUS_ACTIVE = 'active'; const STATUS_INACTIVE = 'inactive'; const STATUS_UNSUBSCRIBED = 'unsubscribed'; const STATUS_BOUNCED = 'bounced'; public static $sourceLabels = [ self::SOURCE_BOOKING_KULTURREISEN => 'Buchung Kulturreisen', self::SOURCE_BOOKING_FERIENWOHNUNGEN => 'Buchung Ferienwohnungen', self::SOURCE_NEWSLETTER_SIGNUP => 'Newsletter-Anmeldung', self::SOURCE_MANUAL => 'Manuell', self::SOURCE_IMPORT => 'Import', ]; public static $statusLabels = [ self::STATUS_ACTIVE => 'Aktiv', self::STATUS_INACTIVE => 'Inaktiv', self::STATUS_UNSUBSCRIBED => 'Abgemeldet', self::STATUS_BOUNCED => 'Bounced', ]; public static $statusColors = [ self::STATUS_ACTIVE => 'success', self::STATUS_INACTIVE => 'secondary', self::STATUS_UNSUBSCRIBED => 'warning', self::STATUS_BOUNCED => 'danger', ]; /** * Beziehung zum Customer (Kulturreisen) */ public function customer() { return $this->belongsTo(Customer::class, 'customer_id'); } /** * Beziehung zum TravelUser (Ferienwohnungen) */ public function travel_user() { return $this->belongsTo(TravelUser::class, 'travel_user_id'); } /** * Logs zu diesem Kontakt */ public function logs() { return $this->hasMany(NewsletterLog::class, 'newsletter_contact_id')->orderBy('created_at', 'DESC'); } /** * Vollständiger Name */ public function getFullNameAttribute() { return trim($this->firstname . ' ' . $this->lastname); } /** * Gruppenzugehörigkeit als Array */ public function getGroupsAttribute() { $groups = []; if ($this->group_kulturreisen) { $groups[] = 'Kulturreisen'; } if ($this->group_ferienwohnungen) { $groups[] = 'Ferienwohnungen'; } return $groups; } /** * Gruppenzugehörigkeit als String */ public function getGroupsStringAttribute() { return implode(', ', $this->groups); } /** * Status-Label */ public function getStatusLabelAttribute() { return self::$statusLabels[$this->status] ?? $this->status; } /** * Status-Color */ public function getStatusColorAttribute() { return self::$statusColors[$this->status] ?? 'secondary'; } /** * Source-Label */ public function getSourceLabelAttribute() { return self::$sourceLabels[$this->source] ?? $this->source; } /** * Status-Badge HTML */ public function getStatusBadgeAttribute() { return '' . $this->status_label . ''; } /** * Gesamtzahl Buchungen */ public function getTotalBookingsAttribute() { return $this->total_bookings_kulturreisen + $this->total_bookings_ferienwohnungen; } /** * Ist Kontakt aktiv? */ public function isActive() { return $this->status === self::STATUS_ACTIVE; } /** * Ist Kontakt abgemeldet? */ public function isUnsubscribed() { return $this->status === self::STATUS_UNSUBSCRIBED; } /** * Hat Kontakt mindestens eine Buchung? */ public function hasBookings() { return $this->total_bookings > 0; } /** * Kontakt abmelden */ public function unsubscribe($reason = null) { $this->status = self::STATUS_UNSUBSCRIBED; $this->unsubscribed_at = now(); $this->save(); // Log erstellen $this->logs()->create([ 'action' => 'unsubscribed', 'description' => $reason ?? 'Kontakt abgemeldet', ]); return $this; } /** * Kontakt wieder aktivieren */ public function resubscribe() { $this->status = self::STATUS_ACTIVE; $this->unsubscribed_at = null; $this->save(); // Log erstellen $this->logs()->create([ 'action' => 'subscribed', 'description' => 'Kontakt wieder aktiviert', ]); return $this; } /** * Hash für Duplikat-Erkennung generieren */ public static function generateSyncHash($email, $source) { return md5(strtolower(trim($email)) . '_' . $source); } /** * Scope: Nur aktive Kontakte */ public function scopeActive($query) { return $query->where('status', self::STATUS_ACTIVE); } /** * Scope: Nur Kulturreisen */ public function scopeKulturreisen($query) { return $query->where('group_kulturreisen', true); } /** * Scope: Nur Ferienwohnungen */ public function scopeFerienwohnungen($query) { return $query->where('group_ferienwohnungen', true); } /** * Scope: Mit Buchungen */ public function scopeWithBookings($query) { return $query->where(function ($q) { $q->where('total_bookings_kulturreisen', '>', 0) ->orWhere('total_bookings_ferienwohnungen', '>', 0); }); } /** * Scope: Mehrfachbucher */ public function scopeMultipleBookers($query) { return $query->where(function ($q) { $q->where('total_bookings_kulturreisen', '>', 1) ->orWhere('total_bookings_ferienwohnungen', '>', 1); }); } }