- Administration & Rollenmanagement: Neuer Admin-Bereich mit Feature-Toggles und Sichtbarkeitseinstellungen pro Rolle (11 Toggles, 24 Visibility-Settings) - AdministrationController mit eigenem Settings-Tab, aus SettingsController extrahiert - Feature-Toggle-Guards in Controllers (Invitation, File, ListGenerator, Comment) und Views (events/show, events/edit, events/create) - Setting::isFeatureEnabled() und isFeatureVisibleFor() Hilfsmethoden - Wiederkehrende Trainings: Täglich/Wöchentlich/2-Wöchentlich mit Ende per Datum oder Anzahl (max. 52), Vorschau im Formular - Event-Serien: Verknüpfung über event_series_id (UUID), Modal-Dialog beim Speichern und Löschen mit Optionen "nur dieses" / "alle folgenden" - Löschen-Button direkt in der Event-Bearbeitung mit Serien-Dialog - DemoDataSeeder: 4 Trainings als Serie mit gemeinsamer event_series_id - Übersetzungen in allen 6 Sprachen (de, en, pl, ru, ar, tr) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1269 lines
70 KiB
PHP
Executable File
1269 lines
70 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Database\Seeders;
|
|
|
|
use App\Enums\CateringStatus;
|
|
use App\Enums\EventStatus;
|
|
use App\Enums\EventType;
|
|
use App\Enums\FinanceCategory;
|
|
use App\Enums\FinanceType;
|
|
use App\Enums\ParticipantStatus;
|
|
use App\Enums\PlayerPosition;
|
|
use App\Enums\UserRole;
|
|
use App\Models\ActivityLog;
|
|
use App\Models\Comment;
|
|
use App\Models\Event;
|
|
use App\Models\EventCarpool;
|
|
use App\Models\EventCarpoolPassenger;
|
|
use App\Models\EventCatering;
|
|
use App\Models\EventParticipant;
|
|
use App\Models\EventPlayerStat;
|
|
use App\Models\EventTimekeeper;
|
|
use App\Models\Faq;
|
|
use App\Models\Finance;
|
|
use App\Models\Location;
|
|
use App\Models\Player;
|
|
use App\Models\Season;
|
|
use App\Models\Team;
|
|
use App\Models\User;
|
|
use Illuminate\Database\Seeder;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Support\Str;
|
|
|
|
class DemoDataSeeder extends Seeder
|
|
{
|
|
public function run(): void
|
|
{
|
|
$admin = $this->seedAdmin();
|
|
$coach = $this->seedCoach();
|
|
$parentRep = $this->seedParentRep();
|
|
$team = $this->seedTeam($coach);
|
|
|
|
$data = $this->playerData();
|
|
$parentUsers = $this->seedParentUsers($data);
|
|
$players = $this->seedPlayers($data, $team);
|
|
$this->seedParentPlayerRelations($data, $players, $parentUsers);
|
|
$this->assignParentRepChild($parentRep, $players);
|
|
|
|
$this->seedSeasons();
|
|
$locations = $this->seedLocations();
|
|
$events = $this->seedEvents($team, $admin, $locations);
|
|
$this->seedParticipants($events, $players, $admin, $parentUsers);
|
|
$this->seedCatering($events, $parentUsers);
|
|
$this->seedTimekeepers($events, $parentUsers);
|
|
$this->seedComments($events, $admin, $coach, $parentUsers);
|
|
$this->seedPlayerStats($events, $players);
|
|
$this->seedCarpools($events, $parentUsers, $players);
|
|
$this->seedFaqs($admin);
|
|
$this->seedFinances($team, $admin, $coach, $parentRep);
|
|
$this->seedActivityLogs($admin, $coach, $team, $events);
|
|
$this->seedSoftDeletedRecords($team);
|
|
}
|
|
|
|
// ─── Admin ─────────────────────────────────────────────
|
|
|
|
private function seedAdmin(): User
|
|
{
|
|
// Wenn bereits ein Admin existiert (z.B. durch Installer erstellt), diesen nutzen
|
|
$existing = User::where('role', UserRole::Admin)->first();
|
|
if ($existing) {
|
|
return $existing;
|
|
}
|
|
|
|
return User::updateOrCreate(
|
|
['email' => env('ADMIN_EMAIL', 'admin@handball.local')],
|
|
[
|
|
'name' => 'Charles Xavier',
|
|
'password' => env('ADMIN_PASSWORD', 'admin1234'),
|
|
'role' => UserRole::Admin,
|
|
'is_active' => true,
|
|
]
|
|
);
|
|
}
|
|
|
|
// ─── Trainer ───────────────────────────────────────────
|
|
|
|
private function seedCoach(): User
|
|
{
|
|
return User::firstOrCreate(
|
|
['email' => 'trainer@handball.local'],
|
|
[
|
|
'name' => 'Nick Fury',
|
|
'password' => Hash::make('trainer1234'),
|
|
'role' => UserRole::Coach,
|
|
'is_active' => true,
|
|
'phone' => '0171-1234567',
|
|
]
|
|
);
|
|
}
|
|
|
|
// ─── Elternvertretung ──────────────────────────────────
|
|
|
|
private function seedParentRep(): User
|
|
{
|
|
return User::firstOrCreate(
|
|
['email' => 'elternvertretung@handball.local'],
|
|
[
|
|
'name' => 'Peggy Carter',
|
|
'password' => Hash::make('eltern1234'),
|
|
'role' => UserRole::ParentRep,
|
|
'is_active' => true,
|
|
'phone' => '0172-9876543',
|
|
]
|
|
);
|
|
}
|
|
|
|
// ─── Team ──────────────────────────────────────────────
|
|
|
|
private function seedTeam(User $coach): Team
|
|
{
|
|
$team = Team::firstOrCreate(
|
|
['name' => 'Mannschaft I'],
|
|
['year_group' => '2017/2018', 'is_active' => true]
|
|
);
|
|
|
|
// Coach via team_user pivot zuweisen
|
|
DB::table('team_user')->updateOrInsert(
|
|
['team_id' => $team->id, 'user_id' => $coach->id],
|
|
['created_at' => now()]
|
|
);
|
|
|
|
return $team;
|
|
}
|
|
|
|
// ─── Datenstruktur ─────────────────────────────────────
|
|
|
|
private function playerData(): array
|
|
{
|
|
// [Kind-Vorname, Nachname, [[Eltern-Vorname, Geschlecht], ...]]
|
|
// Mix aus Disney-, Marvel- und DC-Universum
|
|
return [
|
|
// ── Marvel ──────────────────────────────
|
|
['Peter', 'Parker', [['Mary', 'w']]],
|
|
['Morgan', 'Stark', [['Tony', 'm'], ['Pepper', 'w']]],
|
|
['Cooper', 'Barton', [['Clint', 'm'], ['Laura', 'w']]],
|
|
['Kamala', 'Khan', [['Muneeba', 'w']]],
|
|
['Cassie', 'Lang', [['Scott', 'm']]],
|
|
['Natasha', 'Romanoff', [['Alexei', 'm']]],
|
|
['Wanda', 'Maximoff', [['Natalya', 'w']]],
|
|
['Loki', 'Odinson', [['Frigga', 'w']]],
|
|
['Groot', 'Guardian', [['Rocket', 'm']]],
|
|
// ── DC ──────────────────────────────────
|
|
['Damian', 'Wayne', [['Bruce', 'm'], ['Talia', 'w']]],
|
|
['Jon', 'Kent', [['Clark', 'm'], ['Lois', 'w']]],
|
|
['Barbara', 'Gordon', [['James', 'm']]],
|
|
['Wally', 'West', [['Iris', 'w']]],
|
|
['Arthur', 'Curry', [['Atlanna', 'w']]],
|
|
['Diana', 'Prince', [['Hippolyta', 'w']]],
|
|
['Oliver', 'Queen', [['Moira', 'w']]],
|
|
['Kara', 'Danvers', [['Eliza', 'w']]],
|
|
['Garfield', 'Logan', [['Marie', 'w']]],
|
|
// ── Disney ──────────────────────────────
|
|
['Simba', 'Pride', [['Sarabi', 'w']]],
|
|
['Elsa', 'Arendelle', [['Iduna', 'w']]],
|
|
['Rapunzel', 'Corona', [['Arianna', 'w']]],
|
|
['Moana', 'Motunui', [['Sina', 'w']]],
|
|
['Nemo', 'Reef', [['Marlin', 'm']]],
|
|
['Dash', 'Parr', [['Helen', 'w']]],
|
|
['Raya', 'Kumandra', [['Benja', 'm']]],
|
|
['Mirabel', 'Madrigal', [['Julieta', 'w']]],
|
|
['Riley', 'Andersen', [['Jill', 'w']]],
|
|
];
|
|
}
|
|
|
|
// ─── Eltern-Benutzer ───────────────────────────────────
|
|
|
|
private function seedParentUsers(array $data): array
|
|
{
|
|
$hashedPassword = Hash::make('eltern1234');
|
|
$parentUsers = [];
|
|
$phones = [
|
|
'Mary Parker' => '0151-1111111',
|
|
'Tony Stark' => '0152-2222222',
|
|
'Sarabi Pride' => '0153-3333333',
|
|
'Scott Lang' => '0154-4444444',
|
|
];
|
|
|
|
foreach ($data as [$childFirst, $lastName, $parents]) {
|
|
foreach ($parents as [$parentFirst, $gender]) {
|
|
$fullName = "{$parentFirst} {$lastName}";
|
|
if (isset($parentUsers[$fullName])) {
|
|
continue;
|
|
}
|
|
$email = $this->makeEmail($parentFirst, $lastName);
|
|
$user = User::firstOrCreate(
|
|
['email' => $email],
|
|
[
|
|
'name' => $fullName,
|
|
'password' => $hashedPassword,
|
|
'role' => UserRole::User,
|
|
'is_active' => true,
|
|
'phone' => $phones[$fullName] ?? null,
|
|
]
|
|
);
|
|
$parentUsers[$fullName] = $user;
|
|
}
|
|
}
|
|
|
|
return $parentUsers;
|
|
}
|
|
|
|
// ─── Spieler ───────────────────────────────────────────
|
|
|
|
private function seedPlayers(array $data, Team $team): array
|
|
{
|
|
// Positionsverteilung: Index → Position
|
|
$positions = [
|
|
0 => PlayerPosition::Torwart,
|
|
1 => PlayerPosition::LinksAussen,
|
|
2 => PlayerPosition::RueckraumMitte,
|
|
3 => PlayerPosition::RueckraumLinks,
|
|
4 => PlayerPosition::RechtsAussen,
|
|
5 => PlayerPosition::RueckraumRechts,
|
|
6 => PlayerPosition::Kreislaeufer,
|
|
7 => PlayerPosition::LinksAussen,
|
|
8 => PlayerPosition::RechtsAussen,
|
|
9 => PlayerPosition::RueckraumLinks,
|
|
10 => PlayerPosition::RueckraumMitte,
|
|
11 => PlayerPosition::RueckraumRechts,
|
|
12 => PlayerPosition::Kreislaeufer,
|
|
13 => PlayerPosition::Torwart, // Ersatz-TW
|
|
];
|
|
|
|
$players = [];
|
|
$jerseyNr = 1;
|
|
foreach ($data as $idx => [$childFirst, $lastName, $parents]) {
|
|
$player = Player::firstOrCreate(
|
|
['first_name' => $childFirst, 'last_name' => $lastName, 'team_id' => $team->id],
|
|
[
|
|
'birth_year' => $jerseyNr % 2 === 0 ? 2017 : 2018,
|
|
'jersey_number' => $jerseyNr,
|
|
'is_active' => true,
|
|
'photo_permission' => true,
|
|
'position' => $positions[$idx] ?? null,
|
|
]
|
|
);
|
|
// Position auch bei bestehenden Spielern setzen
|
|
if ($player->position === null && isset($positions[$idx])) {
|
|
$player->update(['position' => $positions[$idx]]);
|
|
}
|
|
$players["{$childFirst} {$lastName}"] = $player;
|
|
$jerseyNr++;
|
|
}
|
|
|
|
return $players;
|
|
}
|
|
|
|
// ─── Eltern-Kind-Zuordnungen ───────────────────────────
|
|
// ACHTUNG: parent_player hat KEIN updated_at → DB::table()->updateOrInsert()
|
|
|
|
private function seedParentPlayerRelations(array $data, array $players, array $parentUsers): void
|
|
{
|
|
foreach ($data as [$childFirst, $lastName, $parents]) {
|
|
$player = $players["{$childFirst} {$lastName}"];
|
|
foreach ($parents as [$parentFirst, $gender]) {
|
|
$user = $parentUsers["{$parentFirst} {$lastName}"];
|
|
DB::table('parent_player')->updateOrInsert(
|
|
['parent_id' => $user->id, 'player_id' => $player->id],
|
|
['relationship_label' => $gender === 'm' ? 'Vater' : 'Mutter', 'created_at' => now()]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ─── Elternvertretung Kind zuweisen ────────────────────
|
|
|
|
private function assignParentRepChild(User $parentRep, array $players): void
|
|
{
|
|
$firstPlayer = reset($players);
|
|
DB::table('parent_player')->updateOrInsert(
|
|
['parent_id' => $parentRep->id, 'player_id' => $firstPlayer->id],
|
|
['relationship_label' => 'Elternvertretung', 'created_at' => now()]
|
|
);
|
|
}
|
|
|
|
// ─── Orte ──────────────────────────────────────────────
|
|
|
|
private function seedLocations(): array
|
|
{
|
|
return [
|
|
Location::firstOrCreate(
|
|
['name' => 'Sporthalle Musterstadt'],
|
|
['address_text' => 'Schulstraße 12, 12345 Musterstadt', 'location_lat' => 50.1109, 'location_lng' => 8.6821]
|
|
),
|
|
Location::firstOrCreate(
|
|
['name' => 'Sporthalle Nachbarort'],
|
|
['address_text' => 'Am Sportpark 5, 12346 Nachbarort', 'location_lat' => 50.1205, 'location_lng' => 8.7100]
|
|
),
|
|
Location::firstOrCreate(
|
|
['name' => 'Turnierzentrum Landeshauptstadt'],
|
|
['address_text' => 'Sportplatzweg 1, 60000 Landeshauptstadt', 'location_lat' => 50.1155, 'location_lng' => 8.6842]
|
|
),
|
|
];
|
|
}
|
|
|
|
// ─── Events ────────────────────────────────────────────
|
|
|
|
private function seedEvents(Team $team, User $admin, array $locations): array
|
|
{
|
|
$events = [];
|
|
|
|
// 0: Training (vergangen)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Training Dienstag', 'team_id' => $team->id, 'start_at' => now()->subDays(3)->setTime(17, 0)],
|
|
[
|
|
'type' => EventType::Training,
|
|
'end_at' => now()->subDays(3)->setTime(18, 30),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'location_lat' => $locations[0]->location_lat,
|
|
'location_lng' => $locations[0]->location_lng,
|
|
'description_html' => '<p>Reguläres Training. Bitte <strong>Hallenschuhe</strong> und ausreichend Trinken mitbringen.</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 1: Training (Zukunft) — Teil einer Trainingsserie
|
|
$trainingSeriesId = (string) Str::uuid();
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Training nächste Woche', 'team_id' => $team->id, 'start_at' => now()->next('Tuesday')->setTime(17, 0)],
|
|
[
|
|
'type' => EventType::Training,
|
|
'end_at' => now()->next('Tuesday')->setTime(18, 30),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'location_lat' => $locations[0]->location_lat,
|
|
'location_lng' => $locations[0]->location_lng,
|
|
'min_players' => 12,
|
|
'min_catering' => 1,
|
|
'min_timekeepers' => 1,
|
|
'event_series_id' => $trainingSeriesId,
|
|
'description_html' => '<p>Training mit Schwerpunkt Passspiel. Bitte pünktlich kommen!</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 2: Heimspiel (vergangen, mit Ergebnis)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Heimspiel vs. TSV Beispielburg', 'team_id' => $team->id, 'start_at' => now()->subWeek()->previous('Saturday')->setTime(10, 0)],
|
|
[
|
|
'type' => EventType::HomeGame,
|
|
'end_at' => now()->subWeek()->previous('Saturday')->setTime(12, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'location_lat' => $locations[0]->location_lat,
|
|
'location_lng' => $locations[0]->location_lng,
|
|
'opponent' => 'TSV Beispielburg',
|
|
'score_home' => 15,
|
|
'score_away' => 12,
|
|
'min_players' => 10,
|
|
'min_catering' => 2,
|
|
'min_timekeepers' => 2,
|
|
'description_html' => '<p>Unser erstes Heimspiel der Rückrunde! Bitte <strong>30 Minuten vor Anpfiff</strong> da sein.</p><ul><li>Trikots werden gestellt</li><li>Eltern bitte Kuchen mitbringen</li></ul>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 3: Auswärtsspiel (Zukunft)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Auswärtsspiel beim SC Nachbarort', 'team_id' => $team->id, 'start_at' => now()->addWeeks(2)->next('Saturday')->setTime(11, 0)],
|
|
[
|
|
'type' => EventType::AwayGame,
|
|
'end_at' => now()->addWeeks(2)->next('Saturday')->setTime(13, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[1]->name,
|
|
'address_text' => $locations[1]->address_text,
|
|
'location_lat' => $locations[1]->location_lat,
|
|
'location_lng' => $locations[1]->location_lng,
|
|
'opponent' => 'SC Nachbarort',
|
|
'min_players' => 10,
|
|
'description_html' => '<p>Auswärtsspiel — Fahrgemeinschaften bitte abstimmen. Treffpunkt 10:00 am Vereinsheim.</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 4: Turnier (Zukunft)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Nikolaus-Turnier Sportverein', 'team_id' => $team->id, 'start_at' => now()->addWeeks(3)->next('Sunday')->setTime(9, 0)],
|
|
[
|
|
'type' => EventType::Tournament,
|
|
'end_at' => now()->addWeeks(3)->next('Sunday')->setTime(16, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[2]->name,
|
|
'address_text' => $locations[2]->address_text,
|
|
'location_lat' => $locations[2]->location_lat,
|
|
'location_lng' => $locations[2]->location_lng,
|
|
'min_players' => 12,
|
|
'min_catering' => 3,
|
|
'min_timekeepers' => 2,
|
|
'description_html' => '<p>Ganztages-Turnier mit 8 Mannschaften. Bitte <strong>Lunchpaket</strong> einpacken.</p><h3>Zeitplan</h3><ul><li>09:00 Eintreffen</li><li>09:30 Erstes Spiel</li><li>ca. 16:00 Siegerehrung</li></ul>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 5: Besprechung (Zukunft)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Elternabend Rückrunden-Planung', 'team_id' => $team->id, 'start_at' => now()->addWeeks(4)->next('Wednesday')->setTime(19, 30)],
|
|
[
|
|
'type' => EventType::Meeting,
|
|
'end_at' => now()->addWeeks(4)->next('Wednesday')->setTime(21, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => 'Vereinsheim TV Musterstadt',
|
|
'address_text' => 'Vereinsweg 1, 12345 Musterstadt',
|
|
'min_players' => 10,
|
|
'description_html' => '<p>Themen:</p><ul><li>Rückrunden-Spielplan</li><li>Trikot-Bestellung</li><li>Fahrgemeinschaften</li><li>Eltern-Catering-Plan</li></ul>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 6: Abgesagtes Training
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Training Donnerstag (entfällt!)', 'team_id' => $team->id, 'start_at' => now()->next('Thursday')->setTime(17, 0)],
|
|
[
|
|
'type' => EventType::Training,
|
|
'end_at' => now()->next('Thursday')->setTime(18, 30),
|
|
'status' => EventStatus::Cancelled,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'description_html' => '<p>Fällt wegen Hallensperrung aus. Nächstes Training wie gewohnt am Dienstag.</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 7: Sonstiges (EventType::Other)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Trikot-Ausgabe & Mannschaftsfoto', 'team_id' => $team->id, 'start_at' => now()->addWeeks(5)->next('Saturday')->setTime(10, 0)],
|
|
[
|
|
'type' => EventType::Other,
|
|
'end_at' => now()->addWeeks(5)->next('Saturday')->setTime(12, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'location_lat' => $locations[0]->location_lat,
|
|
'location_lng' => $locations[0]->location_lng,
|
|
'min_players' => 20,
|
|
'description_html' => '<p>Neue Trikots werden ausgegeben und wir machen das offizielle <strong>Mannschaftsfoto</strong>!</p><ul><li>Bitte alle pünktlich erscheinen</li><li>Helle Hose mitbringen</li><li>Fotografin kommt um 10:30</li></ul>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 8: Entwurf
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Freundschaftsspiel (in Planung)', 'team_id' => $team->id, 'start_at' => now()->addWeeks(6)->next('Saturday')->setTime(10, 0)],
|
|
[
|
|
'type' => EventType::HomeGame,
|
|
'end_at' => now()->addWeeks(6)->next('Saturday')->setTime(12, 0),
|
|
'status' => EventStatus::Draft,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'location_lat' => $locations[0]->location_lat,
|
|
'location_lng' => $locations[0]->location_lng,
|
|
'opponent' => 'TBD',
|
|
'description_html' => '<p>Freundschaftsspiel — Gegner und Uhrzeit werden noch festgelegt.</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 9: Heimspiel (vergangen, 12:10 Sieg)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Heimspiel vs. SG Westend', 'team_id' => $team->id, 'start_at' => now()->subWeeks(5)->previous('Saturday')->setTime(10, 0)],
|
|
[
|
|
'type' => EventType::HomeGame,
|
|
'end_at' => now()->subWeeks(5)->previous('Saturday')->setTime(12, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'location_lat' => $locations[0]->location_lat,
|
|
'location_lng' => $locations[0]->location_lng,
|
|
'opponent' => 'SG Westend',
|
|
'score_home' => 12,
|
|
'score_away' => 10,
|
|
'min_players' => 10,
|
|
'min_catering' => 2,
|
|
'min_timekeepers' => 2,
|
|
'description_html' => '<p>Zweites Heimspiel der Saison. <strong>Wichtig: Hallenschuhe!</strong></p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 10: Auswärtsspiel (vergangen, 8:14 Niederlage)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Auswärtsspiel bei HSG Bergheim', 'team_id' => $team->id, 'start_at' => now()->subWeeks(4)->previous('Saturday')->setTime(11, 0)],
|
|
[
|
|
'type' => EventType::AwayGame,
|
|
'end_at' => now()->subWeeks(4)->previous('Saturday')->setTime(13, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[1]->name,
|
|
'address_text' => $locations[1]->address_text,
|
|
'location_lat' => $locations[1]->location_lat,
|
|
'location_lng' => $locations[1]->location_lng,
|
|
'opponent' => 'HSG Bergheim',
|
|
'score_home' => 8,
|
|
'score_away' => 14,
|
|
'min_players' => 10,
|
|
'description_html' => '<p>Auswärtsspiel. Treffpunkt <strong>10:00 Uhr</strong> am Parkplatz.</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 11: Heimspiel (vergangen, 11:11 Unentschieden)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Heimspiel vs. TV Grüntal', 'team_id' => $team->id, 'start_at' => now()->subWeeks(3)->previous('Saturday')->setTime(10, 0)],
|
|
[
|
|
'type' => EventType::HomeGame,
|
|
'end_at' => now()->subWeeks(3)->previous('Saturday')->setTime(12, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'location_lat' => $locations[0]->location_lat,
|
|
'location_lng' => $locations[0]->location_lng,
|
|
'opponent' => 'TV Grüntal',
|
|
'score_home' => 11,
|
|
'score_away' => 11,
|
|
'min_players' => 10,
|
|
'min_catering' => 2,
|
|
'min_timekeepers' => 2,
|
|
'description_html' => '<p>Spannendes Spiel erwartet! TV Grüntal steht direkt hinter uns in der Tabelle.</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 12: Auswärtsspiel (vergangen, 13:9 Sieg)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Auswärtsspiel bei JSG Adlerhorst', 'team_id' => $team->id, 'start_at' => now()->subDays(18)->setTime(11, 0)],
|
|
[
|
|
'type' => EventType::AwayGame,
|
|
'end_at' => now()->subDays(18)->setTime(13, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[2]->name,
|
|
'address_text' => $locations[2]->address_text,
|
|
'location_lat' => $locations[2]->location_lat,
|
|
'location_lng' => $locations[2]->location_lng,
|
|
'opponent' => 'JSG Adlerhorst',
|
|
'score_home' => 13,
|
|
'score_away' => 9,
|
|
'min_players' => 10,
|
|
'description_html' => '<p>Abfahrt <strong>9:30 Uhr</strong>. Bitte Fahrgemeinschaften bilden.</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// 13: Heimspiel (vergangen, 16:14 Sieg)
|
|
$events[] = Event::updateOrCreate(
|
|
['title' => 'Heimspiel vs. SC Nordpark', 'team_id' => $team->id, 'start_at' => now()->subDays(11)->setTime(10, 0)],
|
|
[
|
|
'type' => EventType::HomeGame,
|
|
'end_at' => now()->subDays(11)->setTime(12, 0),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'location_lat' => $locations[0]->location_lat,
|
|
'location_lng' => $locations[0]->location_lng,
|
|
'opponent' => 'SC Nordpark',
|
|
'score_home' => 16,
|
|
'score_away' => 14,
|
|
'min_players' => 10,
|
|
'min_catering' => 2,
|
|
'min_timekeepers' => 2,
|
|
'description_html' => '<p>Tabellenführer zu Gast! Bitte alle da sein. <strong>Eltern: Kuchen mitbringen</strong>.</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
|
|
// Serien-Folgetermine: 3 weitere Trainings (gleiche event_series_id wie Event 1)
|
|
for ($i = 1; $i <= 3; $i++) {
|
|
$tuesday = now()->next('Tuesday')->addWeeks($i);
|
|
Event::updateOrCreate(
|
|
['title' => 'Training Dienstag (Serie)', 'team_id' => $team->id, 'start_at' => $tuesday->copy()->setTime(17, 0)],
|
|
[
|
|
'type' => EventType::Training,
|
|
'end_at' => $tuesday->copy()->setTime(18, 30),
|
|
'status' => EventStatus::Published,
|
|
'location_name' => $locations[0]->name,
|
|
'address_text' => $locations[0]->address_text,
|
|
'location_lat' => $locations[0]->location_lat,
|
|
'location_lng' => $locations[0]->location_lng,
|
|
'min_players' => 12,
|
|
'min_catering' => 1,
|
|
'min_timekeepers' => 1,
|
|
'event_series_id' => $trainingSeriesId,
|
|
'description_html' => '<p>Wöchentliches Training. Bitte <strong>Hallenschuhe</strong> und ausreichend Trinken mitbringen.</p>',
|
|
'created_by' => $admin->id,
|
|
]
|
|
);
|
|
}
|
|
|
|
return $events;
|
|
}
|
|
|
|
// ─── Teilnehmer ────────────────────────────────────────
|
|
// ACHTUNG: set_by_user_id ist NOT NULL → immer explizit setzen
|
|
|
|
private function seedParticipants(array $events, array $players, User $admin, array $parentUsers): void
|
|
{
|
|
$parentList = array_values($parentUsers);
|
|
$playerList = array_values($players);
|
|
|
|
// Statusverteilungen pro Event-Index: [Ja, Nein, Rest=Offen]
|
|
$distributions = [
|
|
0 => [22, 3], // Training vergangen
|
|
1 => [15, 5], // Training Zukunft
|
|
2 => [18, 4], // Heimspiel vs TSV Beispielburg
|
|
3 => [12, 3], // Auswärtsspiel
|
|
4 => [20, 2], // Turnier
|
|
6 => [5, 2], // Abgesagt
|
|
9 => [20, 3], // Heimspiel vs SG Westend
|
|
10 => [14, 6], // Auswärtsspiel bei HSG Bergheim
|
|
11 => [18, 4], // Heimspiel vs TV Grüntal
|
|
12 => [16, 5], // Auswärtsspiel bei JSG Adlerhorst
|
|
13 => [22, 2], // Heimspiel vs SC Nordpark
|
|
];
|
|
|
|
$sampleNotes = [
|
|
'Komme direkt aus der Schule',
|
|
'Wird eventuell 10 Min. später',
|
|
'Bringt eigene Trinkflasche mit',
|
|
];
|
|
|
|
foreach ($distributions as $eventIdx => $dist) {
|
|
$event = $events[$eventIdx];
|
|
[$yesCount, $noCount] = $dist;
|
|
|
|
foreach (array_values($playerList) as $i => $player) {
|
|
if ($i < $yesCount) {
|
|
$status = ParticipantStatus::Yes;
|
|
} elseif ($i < $yesCount + $noCount) {
|
|
$status = ParticipantStatus::No;
|
|
} else {
|
|
$status = ParticipantStatus::Unknown;
|
|
}
|
|
|
|
$setByUserId = isset($parentList[$i]) ? $parentList[$i]->id : $admin->id;
|
|
$respondedAt = $status !== ParticipantStatus::Unknown ? now()->subHours(rand(1, 72)) : null;
|
|
$note = ($status === ParticipantStatus::Yes && $i < count($sampleNotes)) ? $sampleNotes[$i] : null;
|
|
|
|
$participant = EventParticipant::firstOrNew(
|
|
['event_id' => $event->id, 'player_id' => $player->id]
|
|
);
|
|
$participant->status = $status;
|
|
$participant->set_by_user_id = $setByUserId;
|
|
$participant->responded_at = $respondedAt;
|
|
$participant->note = $note;
|
|
$participant->save();
|
|
}
|
|
}
|
|
|
|
// Besprechung (Index 5): User-basierte Teilnehmer
|
|
$meeting = $events[5];
|
|
$meeting->syncMeetingParticipants($admin->id);
|
|
|
|
$meetingParticipants = EventParticipant::where('event_id', $meeting->id)->get();
|
|
foreach ($meetingParticipants->take(10) as $idx => $p) {
|
|
$p->status = $idx < 7 ? ParticipantStatus::Yes : ParticipantStatus::No;
|
|
$p->set_by_user_id = $p->user_id ?? $admin->id;
|
|
$p->responded_at = now()->subHours(rand(1, 24));
|
|
$p->save();
|
|
}
|
|
}
|
|
|
|
// ─── Catering ──────────────────────────────────────────
|
|
// Kein Catering bei AwayGame und Meeting
|
|
|
|
private function seedCatering(array $events, array $parentUsers): void
|
|
{
|
|
$p = array_values($parentUsers);
|
|
|
|
$entries = [
|
|
[$events[2]->id, $p[0]->id, CateringStatus::Yes, 'Bringe Marmorkuchen mit'],
|
|
[$events[2]->id, $p[1]->id, CateringStatus::Yes, 'Bringe Obst und Wasser mit'],
|
|
[$events[2]->id, $p[2]->id, CateringStatus::No, 'Kann leider nicht'],
|
|
[$events[1]->id, $p[3]->id, CateringStatus::Yes, 'Belegte Brötchen'],
|
|
[$events[1]->id, $p[4]->id, CateringStatus::Unknown, null],
|
|
[$events[4]->id, $p[5]->id, CateringStatus::Yes, 'Kuchen und Muffins'],
|
|
[$events[4]->id, $p[6]->id, CateringStatus::Yes, 'Getränke'],
|
|
[$events[4]->id, $p[7]->id, CateringStatus::No, null],
|
|
// Heimspiel vs SG Westend (9)
|
|
[$events[9]->id, $p[2]->id, CateringStatus::Yes, 'Apfelkuchen'],
|
|
[$events[9]->id, $p[4]->id, CateringStatus::Yes, 'Wasser und Saft'],
|
|
// Heimspiel vs TV Grüntal (11)
|
|
[$events[11]->id, $p[6]->id, CateringStatus::Yes, 'Obstteller'],
|
|
[$events[11]->id, $p[8]->id, CateringStatus::Yes, 'Brezeln und Laugenbrötchen'],
|
|
// Heimspiel vs SC Nordpark (13)
|
|
[$events[13]->id, $p[1]->id, CateringStatus::Yes, 'Pizzaschnecken'],
|
|
[$events[13]->id, $p[3]->id, CateringStatus::Yes, 'Gemüse-Sticks und Dip'],
|
|
[$events[13]->id, $p[9]->id, CateringStatus::Yes, 'Getränke'],
|
|
];
|
|
|
|
foreach ($entries as [$eventId, $userId, $status, $note]) {
|
|
$c = EventCatering::where('event_id', $eventId)->where('user_id', $userId)->first();
|
|
if (!$c) {
|
|
$c = new EventCatering(['event_id' => $eventId]);
|
|
$c->user_id = $userId;
|
|
}
|
|
$c->status = $status;
|
|
$c->note = $note;
|
|
$c->save();
|
|
}
|
|
}
|
|
|
|
// ─── Zeitnehmer ────────────────────────────────────────
|
|
// EventTimekeeper nutzt CateringStatus-Enum
|
|
|
|
private function seedTimekeepers(array $events, array $parentUsers): void
|
|
{
|
|
$p = array_values($parentUsers);
|
|
|
|
$entries = [
|
|
[$events[2]->id, $p[10]->id, CateringStatus::Yes],
|
|
[$events[2]->id, $p[11]->id, CateringStatus::Yes],
|
|
[$events[1]->id, $p[12]->id, CateringStatus::Yes],
|
|
[$events[1]->id, $p[13]->id, CateringStatus::No],
|
|
[$events[4]->id, $p[14]->id, CateringStatus::Yes],
|
|
[$events[4]->id, $p[15]->id, CateringStatus::Unknown],
|
|
// Heimspiel vs SG Westend (9)
|
|
[$events[9]->id, $p[8]->id, CateringStatus::Yes],
|
|
[$events[9]->id, $p[9]->id, CateringStatus::Yes],
|
|
// Heimspiel vs TV Grüntal (11)
|
|
[$events[11]->id, $p[10]->id, CateringStatus::Yes],
|
|
[$events[11]->id, $p[12]->id, CateringStatus::Yes],
|
|
// Heimspiel vs SC Nordpark (13)
|
|
[$events[13]->id, $p[14]->id, CateringStatus::Yes],
|
|
[$events[13]->id, $p[11]->id, CateringStatus::Yes],
|
|
];
|
|
|
|
foreach ($entries as [$eventId, $userId, $status]) {
|
|
$t = EventTimekeeper::where('event_id', $eventId)->where('user_id', $userId)->first();
|
|
if (!$t) {
|
|
$t = new EventTimekeeper(['event_id' => $eventId]);
|
|
$t->user_id = $userId;
|
|
}
|
|
$t->status = $status;
|
|
$t->save();
|
|
}
|
|
}
|
|
|
|
// ─── Kommentare ────────────────────────────────────────
|
|
|
|
private function seedComments(array $events, User $admin, User $coach, array $parentUsers): void
|
|
{
|
|
$p = array_values($parentUsers);
|
|
|
|
// Heimspiel (Index 2): 4 Kommentare
|
|
Comment::updateOrCreate(
|
|
['event_id' => $events[2]->id, 'user_id' => $p[0]->id, 'body' => 'Können wir Fahrgemeinschaften bilden?'],
|
|
['created_at' => now()->subDays(5)->subHours(5)]
|
|
);
|
|
Comment::updateOrCreate(
|
|
['event_id' => $events[2]->id, 'user_id' => $admin->id, 'body' => 'Gute Idee! Bitte untereinander absprechen.'],
|
|
['created_at' => now()->subDays(5)->subHours(3)]
|
|
);
|
|
Comment::updateOrCreate(
|
|
['event_id' => $events[2]->id, 'user_id' => $p[3]->id, 'body' => 'Wir können 3 Kinder mitnehmen.'],
|
|
['created_at' => now()->subDays(5)->subHours(2)]
|
|
);
|
|
Comment::updateOrCreate(
|
|
['event_id' => $events[2]->id, 'user_id' => $coach->id, 'body' => 'Denkt bitte an die Trikots!'],
|
|
['created_at' => now()->subDays(5)->subHour()]
|
|
);
|
|
|
|
// Training Zukunft (Index 1): 2 Kommentare
|
|
Comment::updateOrCreate(
|
|
['event_id' => $events[1]->id, 'user_id' => $p[5]->id, 'body' => 'Kann jemand mein Kind abholen? Bin auf Dienstreise.'],
|
|
['created_at' => now()->subHours(12)]
|
|
);
|
|
Comment::updateOrCreate(
|
|
['event_id' => $events[1]->id, 'user_id' => $p[8]->id, 'body' => 'Klar, kein Problem! Bringe sie mit.'],
|
|
['created_at' => now()->subHours(10)]
|
|
);
|
|
|
|
// Turnier (Index 4): 2 Kommentare
|
|
Comment::updateOrCreate(
|
|
['event_id' => $events[4]->id, 'user_id' => $admin->id, 'body' => 'Zeitplan folgt nächste Woche.'],
|
|
['created_at' => now()->subDays(1)]
|
|
);
|
|
Comment::updateOrCreate(
|
|
['event_id' => $events[4]->id, 'user_id' => $p[2]->id, 'body' => 'Gibt es vor Ort Essen zu kaufen oder sollen wir selber was mitbringen?'],
|
|
['created_at' => now()->subHours(6)]
|
|
);
|
|
|
|
// Besprechung (Index 5): 1 Kommentar
|
|
Comment::updateOrCreate(
|
|
['event_id' => $events[5]->id, 'user_id' => $p[1]->id, 'body' => 'Wird es eine Tagesordnung geben?'],
|
|
['created_at' => now()->subHours(2)]
|
|
);
|
|
|
|
// 1 gelöschter Kommentar (manuelles Soft-Delete via deleted_at + deleted_by)
|
|
$deleted = Comment::updateOrCreate(
|
|
['event_id' => $events[2]->id, 'user_id' => $p[15]->id, 'body' => 'Dieser Kommentar wurde von einem Admin entfernt.'],
|
|
['created_at' => now()->subDays(6)]
|
|
);
|
|
if (! $deleted->isDeleted()) {
|
|
$deleted->update([
|
|
'deleted_at' => now()->subDays(4),
|
|
'deleted_by' => $admin->id,
|
|
]);
|
|
}
|
|
}
|
|
|
|
// ─── Spielerstatistiken ─────────────────────────────────
|
|
// Stats für 6 vergangene Spiele (Index 2, 9, 10, 11, 12, 13)
|
|
|
|
private function seedPlayerStats(array $events, array $players): void
|
|
{
|
|
$playerList = array_values($players);
|
|
|
|
// Format: [index, is_gk, gk_saves, gk_shots, goals, shots, pen_goals, pen_shots, yellow, two_min, minutes, note, position]
|
|
$allStats = [
|
|
// Spiel 2: Heimspiel vs TSV Beispielburg (15:12 Sieg)
|
|
2 => [
|
|
[0, true, 8, 20, 0, 0, null, null, 0, 0, 60, 'Starke Leistung im Tor', 'torwart'],
|
|
[1, false, null, null, 3, 6, 1, 2, 0, 0, 55, 'Drei Tempogegenstöße', 'links_aussen'],
|
|
[2, false, null, null, 2, 5, 0, 1, 1, 0, 50, 'Guter Aufbau', 'rueckraum_mitte'],
|
|
[3, false, null, null, 2, 4, 1, 1, 0, 0, 50, null, 'rueckraum_links'],
|
|
[4, false, null, null, 1, 3, 0, 0, 0, 0, 45, 'Schnelle Beine', 'rechts_aussen'],
|
|
[5, false, null, null, 2, 5, 0, 0, 0, 1, 50, null, 'rueckraum_rechts'],
|
|
[6, false, null, null, 1, 2, 0, 0, 0, 0, 40, 'Erste Tore der Saison!', 'kreislaeufer'],
|
|
[7, false, null, null, 1, 4, 0, 0, 1, 0, 35, null, 'links_aussen'],
|
|
[8, false, null, null, 1, 3, 0, 0, 0, 0, 40, null, 'rechts_aussen'],
|
|
[9, false, null, null, 1, 2, 0, 0, 0, 0, 30, null, 'rueckraum_links'],
|
|
[10, false, null, null, 1, 3, 0, 0, 0, 0, 45, 'Stark in der Abwehr', 'rueckraum_mitte'],
|
|
[11, false, null, null, 0, 2, 0, 0, 0, 0, 25, null, 'rueckraum_rechts'],
|
|
[12, false, null, null, 0, 1, 0, 0, 0, 0, 20, null, 'kreislaeufer'],
|
|
[13, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, 'torwart'],
|
|
[14, false, null, null, 0, 2, 0, 0, 0, 0, 20, 'Erste Spielminuten', null],
|
|
[15, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
[16, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
[17, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
],
|
|
// Spiel 9: Heimspiel vs SG Westend (12:10 Sieg)
|
|
9 => [
|
|
[0, true, 10, 22, 0, 0, null, null, 0, 0, 60, 'Überragend gehalten', 'torwart'],
|
|
[1, false, null, null, 2, 5, 0, 1, 0, 0, 55, null, 'links_aussen'],
|
|
[2, false, null, null, 3, 7, 2, 3, 0, 0, 55, 'Bester Werfer', 'rueckraum_mitte'],
|
|
[3, false, null, null, 1, 3, 0, 0, 1, 0, 45, null, 'rueckraum_links'],
|
|
[4, false, null, null, 1, 4, 0, 0, 0, 0, 50, null, 'rechts_aussen'],
|
|
[5, false, null, null, 2, 4, 0, 0, 0, 0, 50, null, 'rueckraum_rechts'],
|
|
[6, false, null, null, 1, 2, 0, 0, 0, 1, 40, null, 'kreislaeufer'],
|
|
[7, false, null, null, 0, 3, 0, 0, 0, 0, 30, null, 'links_aussen'],
|
|
[8, false, null, null, 1, 2, 0, 0, 0, 0, 35, null, 'rechts_aussen'],
|
|
[9, false, null, null, 0, 1, 0, 0, 0, 0, 25, null, 'rueckraum_links'],
|
|
[10, false, null, null, 1, 3, 0, 0, 0, 0, 40, null, 'rueckraum_mitte'],
|
|
[11, false, null, null, 0, 1, 0, 0, 0, 0, 20, null, 'rueckraum_rechts'],
|
|
[12, false, null, null, 0, 2, 0, 0, 0, 0, 25, null, 'kreislaeufer'],
|
|
[13, false, null, null, 0, 0, 0, 0, 0, 0, 15, null, null],
|
|
[14, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
[15, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
[16, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
[17, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
[18, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
[19, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
],
|
|
// Spiel 10: Auswärtsspiel bei HSG Bergheim (8:14 Niederlage)
|
|
10 => [
|
|
[0, true, 5, 22, 0, 0, null, null, 0, 0, 60, 'Schwieriger Tag', 'torwart'],
|
|
[1, false, null, null, 2, 6, 1, 2, 0, 1, 50, null, 'links_aussen'],
|
|
[2, false, null, null, 1, 5, 0, 0, 1, 0, 50, null, 'rueckraum_mitte'],
|
|
[3, false, null, null, 1, 4, 0, 1, 0, 0, 45, null, 'rueckraum_links'],
|
|
[4, false, null, null, 1, 3, 0, 0, 0, 0, 45, null, 'rechts_aussen'],
|
|
[5, false, null, null, 1, 4, 0, 0, 1, 1, 40, '2-Min wegen Foul', 'rueckraum_rechts'],
|
|
[6, false, null, null, 1, 3, 0, 0, 0, 0, 35, null, 'kreislaeufer'],
|
|
[7, false, null, null, 0, 2, 0, 0, 0, 0, 30, null, 'links_aussen'],
|
|
[8, false, null, null, 1, 3, 0, 0, 0, 0, 35, null, 'rechts_aussen'],
|
|
[9, false, null, null, 0, 2, 0, 0, 0, 0, 25, null, 'rueckraum_links'],
|
|
[10, false, null, null, 0, 2, 0, 0, 0, 0, 35, null, 'rueckraum_mitte'],
|
|
[13, true, 3, 8, 0, 0, null, null, 0, 0, 20, 'Ersatz-TW 2. Halbzeit', 'torwart'],
|
|
[11, false, null, null, 0, 1, 0, 0, 0, 0, 20, null, 'kreislaeufer'],
|
|
[14, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
],
|
|
// Spiel 11: Heimspiel vs TV Grüntal (11:11 Unentschieden)
|
|
11 => [
|
|
[0, true, 9, 22, 0, 0, null, null, 0, 0, 60, 'Klasse gehalten', 'torwart'],
|
|
[1, false, null, null, 2, 5, 1, 1, 0, 0, 55, null, 'links_aussen'],
|
|
[2, false, null, null, 2, 6, 0, 1, 0, 0, 55, null, 'rueckraum_mitte'],
|
|
[3, false, null, null, 2, 4, 1, 2, 0, 0, 50, 'Starke 7-Meter', 'rueckraum_links'],
|
|
[4, false, null, null, 1, 3, 0, 0, 0, 0, 45, null, 'rechts_aussen'],
|
|
[5, false, null, null, 1, 4, 0, 0, 0, 0, 50, null, 'rueckraum_rechts'],
|
|
[6, false, null, null, 1, 2, 0, 0, 1, 0, 40, null, 'kreislaeufer'],
|
|
[7, false, null, null, 1, 3, 0, 0, 0, 0, 35, null, 'links_aussen'],
|
|
[8, false, null, null, 0, 2, 0, 0, 0, 0, 30, null, 'rechts_aussen'],
|
|
[9, false, null, null, 0, 1, 0, 0, 0, 0, 25, null, 'rueckraum_links'],
|
|
[10, false, null, null, 1, 2, 0, 0, 0, 0, 40, null, 'rueckraum_mitte'],
|
|
[11, false, null, null, 0, 1, 0, 0, 0, 0, 20, null, 'rueckraum_rechts'],
|
|
[12, false, null, null, 0, 2, 0, 0, 0, 0, 25, null, 'kreislaeufer'],
|
|
[13, false, null, null, 0, 0, 0, 0, 0, 0, 15, null, null],
|
|
[14, false, null, null, 0, 1, 0, 0, 0, 0, 20, null, null],
|
|
[15, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
[16, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
[17, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
],
|
|
// Spiel 12: Auswärtsspiel bei JSG Adlerhorst (13:9 Sieg)
|
|
12 => [
|
|
[0, true, 11, 20, 0, 0, null, null, 0, 0, 60, 'Bestes Spiel der Saison!', 'torwart'],
|
|
[1, false, null, null, 3, 5, 2, 2, 0, 0, 55, 'Perfekte 7-Meter-Quote', 'links_aussen'],
|
|
[2, false, null, null, 2, 4, 0, 0, 0, 0, 50, null, 'rueckraum_mitte'],
|
|
[3, false, null, null, 2, 4, 0, 0, 0, 0, 50, null, 'rueckraum_links'],
|
|
[4, false, null, null, 2, 4, 0, 0, 0, 0, 50, 'Doppelpack!', 'rechts_aussen'],
|
|
[5, false, null, null, 1, 3, 0, 0, 0, 0, 45, null, 'rueckraum_rechts'],
|
|
[6, false, null, null, 1, 2, 0, 0, 0, 0, 40, null, 'kreislaeufer'],
|
|
[7, false, null, null, 1, 3, 0, 0, 1, 0, 35, null, 'links_aussen'],
|
|
[8, false, null, null, 0, 2, 0, 0, 0, 0, 30, null, 'rechts_aussen'],
|
|
[9, false, null, null, 1, 2, 0, 0, 0, 0, 30, null, 'rueckraum_links'],
|
|
[10, false, null, null, 0, 2, 0, 0, 0, 0, 35, null, 'rueckraum_mitte'],
|
|
[11, false, null, null, 0, 1, 0, 0, 0, 0, 20, null, 'rueckraum_rechts'],
|
|
[12, false, null, null, 0, 1, 0, 0, 0, 0, 20, null, 'kreislaeufer'],
|
|
[13, false, null, null, 0, 0, 0, 0, 0, 0, 15, null, null],
|
|
[14, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
[15, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
],
|
|
// Spiel 13: Heimspiel vs SC Nordpark (16:14 Sieg)
|
|
13 => [
|
|
[0, true, 7, 24, 0, 0, null, null, 0, 0, 50, null, 'torwart'],
|
|
[13, true, 4, 10, 0, 0, null, null, 0, 0, 20, 'Guter Einsatz als Ersatz-TW', 'torwart'],
|
|
[1, false, null, null, 4, 7, 2, 3, 0, 0, 55, 'Überragend!', 'links_aussen'],
|
|
[2, false, null, null, 3, 6, 1, 1, 0, 0, 55, null, 'rueckraum_mitte'],
|
|
[3, false, null, null, 2, 5, 0, 0, 0, 1, 50, null, 'rueckraum_links'],
|
|
[4, false, null, null, 2, 4, 0, 0, 0, 0, 50, null, 'rechts_aussen'],
|
|
[5, false, null, null, 1, 4, 0, 0, 1, 0, 50, null, 'rueckraum_rechts'],
|
|
[6, false, null, null, 1, 3, 0, 0, 0, 0, 45, null, 'kreislaeufer'],
|
|
[7, false, null, null, 1, 2, 0, 0, 0, 0, 35, null, 'links_aussen'],
|
|
[8, false, null, null, 1, 3, 0, 0, 0, 0, 40, null, 'rechts_aussen'],
|
|
[9, false, null, null, 0, 2, 0, 0, 0, 0, 30, null, 'rueckraum_links'],
|
|
[10, false, null, null, 1, 3, 0, 0, 0, 0, 45, null, 'rueckraum_mitte'],
|
|
[11, false, null, null, 0, 1, 0, 0, 0, 0, 25, null, 'rueckraum_rechts'],
|
|
[12, false, null, null, 0, 2, 0, 0, 0, 0, 25, null, 'kreislaeufer'],
|
|
[14, false, null, null, 0, 1, 0, 0, 0, 0, 20, null, null],
|
|
[15, false, null, null, 0, 0, 0, 0, 0, 0, 15, null, null],
|
|
[16, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
[17, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
[18, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
[19, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
[20, false, null, null, 0, 0, 0, 0, 0, 0, 10, null, null],
|
|
[21, false, null, null, 0, 1, 0, 0, 0, 0, 15, null, null],
|
|
],
|
|
];
|
|
|
|
foreach ($allStats as $eventIdx => $statsData) {
|
|
$event = $events[$eventIdx];
|
|
foreach ($statsData as [$idx, $isGk, $gkSaves, $gkShots, $goals, $shots, $penGoals, $penShots, $yellow, $twoMin, $minutes, $note, $position]) {
|
|
if (!isset($playerList[$idx])) {
|
|
continue;
|
|
}
|
|
EventPlayerStat::updateOrCreate(
|
|
['event_id' => $event->id, 'player_id' => $playerList[$idx]->id],
|
|
[
|
|
'is_goalkeeper' => $isGk,
|
|
'goalkeeper_saves' => $gkSaves,
|
|
'goalkeeper_shots' => $gkShots,
|
|
'goals' => $goals,
|
|
'shots' => $shots,
|
|
'penalty_goals' => $penGoals,
|
|
'penalty_shots' => $penShots,
|
|
'yellow_cards' => $yellow,
|
|
'two_minute_suspensions' => $twoMin,
|
|
'playing_time_minutes' => $minutes,
|
|
'note' => $note,
|
|
'position' => $position,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ─── Fahrgemeinschaften ──────────────────────────────────
|
|
// Auswärtsspiel (Index 3) + Turnier (Index 4)
|
|
|
|
private function seedCarpools(array $events, array $parentUsers, array $players): void
|
|
{
|
|
$p = array_values($parentUsers);
|
|
$pl = array_values($players);
|
|
|
|
// Auswärtsspiel (Index 3): 2 Fahrgemeinschaften
|
|
$carpool1 = EventCarpool::where('event_id', $events[3]->id)->where('user_id', $p[0]->id)->first();
|
|
if (!$carpool1) {
|
|
$carpool1 = new EventCarpool(['event_id' => $events[3]->id, 'seats' => 3, 'note' => 'Treffpunkt Parkplatz, 9:30 Uhr']);
|
|
$carpool1->user_id = $p[0]->id;
|
|
$carpool1->save();
|
|
}
|
|
|
|
// 2 Kinder zuordnen
|
|
foreach ([0, 1] as $childIdx) {
|
|
if (isset($pl[$childIdx])) {
|
|
$pass = EventCarpoolPassenger::where('carpool_id', $carpool1->id)->where('player_id', $pl[$childIdx]->id)->first();
|
|
if (!$pass) {
|
|
$pass = new EventCarpoolPassenger(['carpool_id' => $carpool1->id, 'player_id' => $pl[$childIdx]->id]);
|
|
$pass->added_by = $p[0]->id;
|
|
$pass->save();
|
|
}
|
|
}
|
|
}
|
|
|
|
$carpool2 = EventCarpool::where('event_id', $events[3]->id)->where('user_id', $p[2]->id)->first();
|
|
if (!$carpool2) {
|
|
$carpool2 = new EventCarpool(['event_id' => $events[3]->id, 'seats' => 2, 'note' => 'Abfahrt 9:15 Uhr ab Vereinsheim']);
|
|
$carpool2->user_id = $p[2]->id;
|
|
$carpool2->save();
|
|
}
|
|
|
|
// Voll belegt — 2 Kinder
|
|
foreach ([2, 3] as $childIdx) {
|
|
if (isset($pl[$childIdx])) {
|
|
$pass = EventCarpoolPassenger::where('carpool_id', $carpool2->id)->where('player_id', $pl[$childIdx]->id)->first();
|
|
if (!$pass) {
|
|
$pass = new EventCarpoolPassenger(['carpool_id' => $carpool2->id, 'player_id' => $pl[$childIdx]->id]);
|
|
$pass->added_by = $p[2]->id;
|
|
$pass->save();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Turnier (Index 4): 1 Fahrgemeinschaft
|
|
$carpool3 = EventCarpool::where('event_id', $events[4]->id)->where('user_id', $p[5]->id)->first();
|
|
if (!$carpool3) {
|
|
$carpool3 = new EventCarpool(['event_id' => $events[4]->id, 'seats' => 4, 'note' => 'Großer Van, Abfahrt 8:00 Uhr']);
|
|
$carpool3->user_id = $p[5]->id;
|
|
$carpool3->save();
|
|
}
|
|
|
|
// 1 Kind zugeordnet
|
|
if (isset($pl[5])) {
|
|
$pass = EventCarpoolPassenger::where('carpool_id', $carpool3->id)->where('player_id', $pl[5]->id)->first();
|
|
if (!$pass) {
|
|
$pass = new EventCarpoolPassenger(['carpool_id' => $carpool3->id, 'player_id' => $pl[5]->id]);
|
|
$pass->added_by = $p[5]->id;
|
|
$pass->save();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ─── FAQs ──────────────────────────────────────────────
|
|
|
|
private function seedFaqs(User $admin): void
|
|
{
|
|
$faqs = [
|
|
['title' => 'Wie melde ich mein Kind für ein Event an?', 'content_html' => '<p>Gehe auf die Event-Detailseite und klicke bei deinem Kind auf <strong>"Zusagen"</strong>. Du kannst den Status jederzeit ändern.</p><p>Bitte gib so früh wie möglich Bescheid, damit der Trainer planen kann.</p>', 'sort_order' => 1],
|
|
['title' => 'Wie funktioniert das Catering?', 'content_html' => '<p>Bei Heimspielen und Turnieren wird Catering organisiert. Du kannst auf der Event-Seite angeben, ob du etwas mitbringst und was genau.</p><p>Typische Beiträge sind Kuchen, Obst, Getränke oder belegte Brötchen.</p>', 'sort_order' => 2],
|
|
['title' => 'Was ist ein Zeitnehmer?', 'content_html' => '<p>Bei Heimspielen werden <strong>Zeitnehmer</strong> benötigt, die die Spieluhr bedienen. Pro Spiel brauchen wir mindestens 2 Zeitnehmer aus den Reihen der Eltern.</p><p>Keine Sorge — es wird vorher eine kurze Einweisung gegeben!</p>', 'sort_order' => 3],
|
|
['title' => 'Wie funktionieren Fahrgemeinschaften?', 'content_html' => '<p>Bei Auswärtsspielen und Turnieren können Eltern <strong>Fahrgemeinschaften</strong> anbieten. Gehe auf die Event-Detailseite und trage ein, wie viele Plätze du anbieten kannst.</p><p>Andere Eltern können dann ihre Kinder für die Mitfahrt eintragen.</p>', 'sort_order' => 4],
|
|
['title' => 'Wo finde ich die Spielerstatistiken?', 'content_html' => '<p>Im Admin-Bereich unter <strong>"Statistik"</strong> findest du eine Übersicht aller Spieler mit Toren, Würfen und Torwart-Statistiken.</p><p>Die Statistiken können nach Saison, Zeitraum und Team gefiltert werden.</p>', 'sort_order' => 5],
|
|
['title' => 'Kann ich mein Profil bearbeiten?', 'content_html' => '<p>Ja! Klicke oben rechts auf deinen Namen und dann auf <strong>"Profil"</strong>. Dort kannst du:</p><ul><li>Deinen Namen und Telefonnummer ändern</li><li>Ein Profilbild hochladen</li><li>Dein Passwort ändern</li><li>Die Sprache der App umstellen</li></ul>', 'sort_order' => 6],
|
|
['title' => 'Was passiert wenn ich absage?', 'content_html' => '<p>Kein Problem! Absagen sind wichtig, damit der Trainer rechtzeitig planen kann. Bitte sage so früh wie möglich ab.</p><p>Du kannst auch eine <strong>Notiz</strong> hinterlassen (z.B. "krank" oder "Familienfeier").</p>', 'sort_order' => 7],
|
|
];
|
|
|
|
foreach ($faqs as $data) {
|
|
$existing = Faq::where('title', $data['title'])->first();
|
|
if (! $existing) {
|
|
$faq = new Faq([
|
|
'title' => $data['title'],
|
|
'content_html' => $data['content_html'],
|
|
'sort_order' => $data['sort_order'],
|
|
]);
|
|
$faq->created_by = $admin->id;
|
|
$faq->save();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ─── Aktivitätslog ─────────────────────────────────────
|
|
// ActivityLog: $timestamps = false, created_at muss explizit gesetzt werden
|
|
|
|
private function seedActivityLogs(User $admin, User $coach, Team $team, array $events): void
|
|
{
|
|
$base = now()->subDays(7);
|
|
|
|
$logs = [
|
|
['user_id' => $admin->id, 'action' => 'install', 'description' => 'App wurde installiert', 'ip_address' => '127.0.0.1', 'created_at' => $base],
|
|
['user_id' => $admin->id, 'action' => 'login', 'description' => 'Admin hat sich eingeloggt', 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addHour()],
|
|
['user_id' => $admin->id, 'action' => 'created', 'model_type' => 'Team', 'model_id' => $team->id, 'description' => "Team '{$team->name}' erstellt", 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addHours(2)],
|
|
['user_id' => $admin->id, 'action' => 'created', 'model_type' => 'Event', 'model_id' => $events[0]->id, 'description' => "Event '{$events[0]->title}' erstellt", 'properties' => ['new' => ['title' => $events[0]->title, 'type' => 'training']], 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addHours(3)],
|
|
['user_id' => $admin->id, 'action' => 'updated', 'model_type' => 'Event', 'model_id' => $events[2]->id, 'description' => "Event '{$events[2]->title}' bearbeitet", 'properties' => ['old' => ['min_players' => null], 'new' => ['min_players' => 10]], 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addHours(4)],
|
|
['user_id' => $admin->id, 'action' => 'updated', 'model_type' => 'Setting', 'description' => 'Einstellungen aktualisiert', 'properties' => ['old' => ['app_name' => 'Handball App'], 'new' => ['app_name' => 'Demo Handball']], 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addDay()],
|
|
['user_id' => $coach->id, 'action' => 'login', 'description' => 'Trainer hat sich eingeloggt', 'ip_address' => '192.168.1.50', 'created_at' => $base->copy()->addDays(2)],
|
|
['user_id' => $admin->id, 'action' => 'created', 'model_type' => 'Player', 'model_id' => 1, 'description' => 'Spieler erstellt', 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addDays(2)->addHour()],
|
|
['user_id' => $admin->id, 'action' => 'updated', 'model_type' => 'User', 'model_id' => $coach->id, 'description' => "Rolle von '{$coach->name}' geändert", 'properties' => ['old' => ['role' => 'user'], 'new' => ['role' => 'coach']], 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addDays(3)],
|
|
['user_id' => $admin->id, 'action' => 'updated', 'model_type' => 'Event', 'model_id' => $events[6]->id, 'description' => 'Event abgesagt', 'properties' => ['old' => ['status' => 'published'], 'new' => ['status' => 'cancelled']], 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addDays(4)],
|
|
['user_id' => $admin->id, 'action' => 'deleted', 'model_type' => 'User', 'description' => 'Benutzer gelöscht (Soft-Delete)', 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addDays(5)],
|
|
['user_id' => $admin->id, 'action' => 'created', 'model_type' => 'File', 'description' => 'Datei "Regelwerk_Handball.pdf" hochgeladen', 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addDays(6)],
|
|
['user_id' => $admin->id, 'action' => 'season_created', 'model_type' => 'Season', 'description' => 'Saison "2025/2026" erstellt', 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addDays(6)->addHours(2)],
|
|
['user_id' => $admin->id, 'action' => 'finance_created', 'model_type' => 'Finance', 'description' => 'income: Hauptsponsor Saison 2025/2026', 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addDays(6)->addHours(3)],
|
|
['user_id' => $coach->id, 'action' => 'finance_created', 'model_type' => 'Finance', 'description' => 'expense: Neue Handbälle (10 Stück)', 'ip_address' => '192.168.1.50', 'created_at' => $base->copy()->addDays(6)->addHours(4)],
|
|
['user_id' => $admin->id, 'action' => 'finance_updated', 'model_type' => 'Finance', 'description' => 'income: Hauptsponsor Saison 2025/2026', 'properties' => ['before' => ['amount' => 80000], 'after' => ['amount' => 100000]], 'ip_address' => '127.0.0.1', 'created_at' => $base->copy()->addDays(6)->addHours(5)],
|
|
];
|
|
|
|
foreach ($logs as $log) {
|
|
$exists = ActivityLog::where('description', $log['description'])
|
|
->where('created_at', $log['created_at'])
|
|
->exists();
|
|
|
|
if (! $exists) {
|
|
ActivityLog::create($log);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ─── Soft-Deleted Records ──────────────────────────────
|
|
|
|
private function seedSoftDeletedRecords(Team $team): void
|
|
{
|
|
// Gelöschter User (3 Tage, im restaurierbaren 7-Tage-Fenster)
|
|
$deletedUser = User::withTrashed()->firstOrCreate(
|
|
['email' => 'geloescht@handball.local'],
|
|
[
|
|
'name' => 'Thaddeus Ross',
|
|
'password' => Hash::make('geloescht1234'),
|
|
'role' => UserRole::User,
|
|
'is_active' => true,
|
|
]
|
|
);
|
|
if (! $deletedUser->trashed()) {
|
|
$deletedUser->delete();
|
|
User::withTrashed()->where('id', $deletedUser->id)
|
|
->update(['deleted_at' => now()->subDays(3)]);
|
|
}
|
|
|
|
// Gelöschter Spieler (2 Tage, im restaurierbaren 7-Tage-Fenster)
|
|
$deletedPlayer = Player::withTrashed()->firstOrCreate(
|
|
['first_name' => 'Bucky', 'last_name' => 'Barnes', 'team_id' => $team->id],
|
|
[
|
|
'birth_year' => 2017,
|
|
'is_active' => true,
|
|
'photo_permission' => false,
|
|
]
|
|
);
|
|
if (! $deletedPlayer->trashed()) {
|
|
$deletedPlayer->delete();
|
|
Player::withTrashed()->where('id', $deletedPlayer->id)
|
|
->update(['deleted_at' => now()->subDays(2)]);
|
|
}
|
|
}
|
|
|
|
// ─── Helper ────────────────────────────────────────────
|
|
|
|
private function makeEmail(string $first, string $last): string
|
|
{
|
|
$map = ['ß' => 'ss', 'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue',
|
|
'Ä' => 'ae', 'Ö' => 'oe', 'Ü' => 'ue'];
|
|
$f = mb_strtolower(strtr($first, $map));
|
|
$l = mb_strtolower(strtr($last, $map));
|
|
|
|
return "{$f}.{$l}@handball.local";
|
|
}
|
|
|
|
// ─── Saisons ──────────────────────────────────────────
|
|
|
|
private function seedSeasons(): void
|
|
{
|
|
Season::firstOrCreate(
|
|
['name' => '2024/2025'],
|
|
['start_date' => '2024-09-01', 'end_date' => '2025-06-30', 'is_current' => false]
|
|
);
|
|
|
|
Season::firstOrCreate(
|
|
['name' => '2025/2026'],
|
|
['start_date' => '2025-09-01', 'end_date' => '2026-06-30', 'is_current' => true]
|
|
);
|
|
}
|
|
|
|
// ─── Finanzen ─────────────────────────────────────────
|
|
|
|
private function seedFinances(Team $team, User $admin, User $coach, User $parentRep): void
|
|
{
|
|
// [type, category, title, amount_cents, date, created_by, team_id (null=übergreifend), notes]
|
|
$entries = [
|
|
// ─── Saison 2024/2025 (Vorjahr) ─────────────────────────
|
|
// Einnahmen
|
|
['income', 'sponsoring', 'Hauptsponsor Saison 2024/2025', 80000, '2024-09-01', $admin->id, $team->id, 'Vertrag über 2 Jahre'],
|
|
['income', 'membership', 'Mitgliedsbeiträge Herbst 2024', 52000, '2024-10-01', $admin->id, $team->id, null],
|
|
['income', 'catering', 'Catering Heimspiel vs. SG Westend', 9500, '2024-10-19', $parentRep->id, $team->id, 'Kuchen + Getränke'],
|
|
['income', 'catering', 'Kuchenverkauf Adventsturnier', 15500, '2024-12-07', $parentRep->id, $team->id, null],
|
|
['income', 'events', 'Eintritt Weihnachtsfeier 2024', 12000, '2024-12-21', $coach->id, $team->id, null],
|
|
['income', 'membership', 'Mitgliedsbeiträge Frühjahr 2025', 52000, '2025-01-15', $admin->id, $team->id, null],
|
|
['income', 'sponsoring', 'Bandenwerbung Sporthalle', 25000, '2025-02-01', $admin->id, null, 'Vereinsübergreifend'],
|
|
['income', 'tournament_fees', 'Startgeld-Rückerstattung Turnier', 3500, '2025-03-10', $coach->id, $team->id, 'Turnier abgesagt, Erstattung erhalten'],
|
|
['income', 'catering', 'Catering Heimspiel vs. TV Grünberg', 8200, '2025-04-05', $parentRep->id, $team->id, null],
|
|
['income', 'other', 'Spende Elternschaft', 20000, '2025-05-20', $admin->id, $team->id, 'Für neue Trikots'],
|
|
|
|
// Ausgaben
|
|
['expense', 'venue_rental', 'Hallenmiete Sep-Dez 2024', 72000, '2024-09-15', $admin->id, $team->id, '4 Monate à 180€'],
|
|
['expense', 'equipment', 'Handbälle Größe 0 (12 Stück)', 17940, '2024-09-20', $coach->id, $team->id, 'Select Solera'],
|
|
['expense', 'training_material','Koordinationsleiter + Hütchen-Set', 5990, '2024-10-05', $coach->id, $team->id, null],
|
|
['expense', 'tournament_fees', 'Anmeldegebühr Adventsturnier', 5000, '2024-11-01', $coach->id, $team->id, null],
|
|
['expense', 'transport', 'Busfahrt Auswärtsspiel Bergheim', 28000, '2024-11-16', $admin->id, $team->id, null],
|
|
['expense', 'venue_rental', 'Hallenmiete Jan-Jun 2025', 108000, '2025-01-10', $admin->id, $team->id, '6 Monate à 180€'],
|
|
['expense', 'equipment', 'Tornetze Ersatz (2 Stück)', 12500, '2025-02-15', $admin->id, $team->id, null],
|
|
['expense', 'other', 'Schiedsrichterkosten Rückrunde', 9000, '2025-03-01', $admin->id, $team->id, '6 Heimspiele à 15€'],
|
|
['expense', 'transport', 'Fahrtkostenzuschuss Trainer', 15000, '2025-04-01', $admin->id, null, 'Vereinsübergreifend, monatlich'],
|
|
['expense', 'events', 'Saisonabschlussfeier 2024/2025', 22000, '2025-06-28', $parentRep->id, $team->id, 'Grillpaket + Getränke'],
|
|
|
|
// ─── Saison 2025/2026 (aktuell) ──────────────────────────
|
|
// Einnahmen — September
|
|
['income', 'sponsoring', 'Hauptsponsor Saison 2025/2026', 100000, '2025-09-01', $admin->id, $team->id, 'Vertrag verlängert, +200€'],
|
|
['income', 'sponsoring', 'Trikotsponsoring Autohaus Schmidt', 30000, '2025-09-15', $admin->id, $team->id, null],
|
|
['income', 'membership', 'Mitgliedsbeiträge Herbst 2025', 58000, '2025-09-20', $admin->id, $team->id, '29 Spieler à 20€'],
|
|
|
|
// Einnahmen — Oktober
|
|
['income', 'catering', 'Catering Heimspiel vs. HSG Musterstadt', 8500, '2025-10-12', $parentRep->id, $team->id, 'Kuchen + Kaffee'],
|
|
['income', 'other', 'Spende Förderverein', 15000, '2025-10-15', $admin->id, null, 'Vereinsübergreifende Förderung'],
|
|
|
|
// Einnahmen — November
|
|
['income', 'catering', 'Kuchenverkauf Herbstturnier', 12050, '2025-11-15', $parentRep->id, $team->id, 'Rekord! 24 Kuchen verkauft'],
|
|
['income', 'catering', 'Catering Heimspiel vs. TV Adler', 7200, '2025-11-23', $parentRep->id, $team->id, null],
|
|
|
|
// Einnahmen — Dezember
|
|
['income', 'events', 'Einnahmen Weihnachtsfeier', 18500, '2025-12-20', $coach->id, $team->id, 'Tombola + Getränkeverkauf'],
|
|
['income', 'sponsoring', 'Weihnachtsspende Bäckerei Müller', 10000, '2025-12-22', $admin->id, $team->id, null],
|
|
|
|
// Einnahmen — Januar/Februar 2026
|
|
['income', 'membership', 'Mitgliedsbeiträge Frühjahr 2026', 58000, '2026-01-10', $admin->id, $team->id, null],
|
|
['income', 'catering', 'Catering Heimspiel vs. SC Nordpark', 6800, '2026-01-25', $parentRep->id, $team->id, null],
|
|
['income', 'tournament_fees', 'Startgeld Hallenturnier (Veranstalter)', 24000, '2026-02-08', $coach->id, $team->id, '8 Teams à 30€'],
|
|
['income', 'catering', 'Kuchenverkauf Hallenturnier', 19500, '2026-02-08', $parentRep->id, $team->id, 'Ganztagesturnier — sehr guter Umsatz'],
|
|
|
|
// Ausgaben — September
|
|
['expense', 'equipment', 'Trikotdruck Rückennummern', 18500, '2025-09-05', $admin->id, $team->id, 'Satz Heim + Auswärts'],
|
|
['expense', 'equipment', 'Neue Handbälle (10 Stück)', 24990, '2025-09-10', $coach->id, $team->id, 'Select Solera Größe 0'],
|
|
['expense', 'training_material','Hütchen, Leibchen, Koordinationsleiter', 4500, '2025-09-20', $coach->id, $team->id, null],
|
|
['expense', 'venue_rental', 'Hallenmiete September 2025', 18000, '2025-09-25', $admin->id, $team->id, null],
|
|
|
|
// Ausgaben — Oktober
|
|
['expense', 'venue_rental', 'Hallenmiete Oktober 2025', 18000, '2025-10-01', $admin->id, $team->id, null],
|
|
['expense', 'tournament_fees', 'Teilnahme Herbstcup', 7500, '2025-10-20', $coach->id, $team->id, null],
|
|
['expense', 'transport', 'Busfahrt Auswärtsspiel Musterstadt', 32000, '2025-10-26', $admin->id, $team->id, 'Reisebus 50 Plätze'],
|
|
|
|
// Ausgaben — November
|
|
['expense', 'venue_rental', 'Hallenmiete November 2025', 18000, '2025-11-01', $admin->id, $team->id, null],
|
|
['expense', 'other', 'Schiedsrichterkosten 3 Heimspiele', 6000, '2025-11-30', $admin->id, $team->id, null],
|
|
['expense', 'equipment', 'Torwarthandschuhe (2 Paar)', 7980, '2025-11-10', $coach->id, $team->id, 'Kempa Caution'],
|
|
|
|
// Ausgaben — Dezember
|
|
['expense', 'venue_rental', 'Hallenmiete Dezember 2025', 18000, '2025-12-01', $admin->id, $team->id, null],
|
|
['expense', 'events', 'Material Weihnachtsfeier', 8500, '2025-12-18', $parentRep->id, $team->id, 'Deko, Geschenke, Nikolaus'],
|
|
['expense', 'other', 'Versicherung Vereinshaftpflicht', 35000, '2025-12-15', $admin->id, null, 'Vereinsübergreifend, jährlich'],
|
|
|
|
// Ausgaben — Januar/Februar 2026
|
|
['expense', 'venue_rental', 'Hallenmiete Januar 2026', 18000, '2026-01-05', $admin->id, $team->id, null],
|
|
['expense', 'transport', 'Busfahrt Auswärtsspiel Südstadt', 24000, '2026-01-18', $admin->id, $team->id, null],
|
|
['expense', 'venue_rental', 'Hallenmiete Februar 2026', 18000, '2026-02-01', $admin->id, $team->id, null],
|
|
['expense', 'tournament_fees', 'Hallenmiete Zusatzstunden Turnier', 12000, '2026-02-06', $coach->id, $team->id, 'Ganztages-Hallennutzung'],
|
|
['expense', 'training_material','Markierungshütchen Nachbestellung', 1990, '2026-02-20', $coach->id, $team->id, null],
|
|
];
|
|
|
|
foreach ($entries as [$type, $category, $title, $amount, $date, $createdBy, $teamId, $notes]) {
|
|
Finance::firstOrCreate(
|
|
['title' => $title, 'date' => $date],
|
|
[
|
|
'team_id' => $teamId,
|
|
'type' => $type,
|
|
'category' => $category,
|
|
'amount' => $amount,
|
|
'notes' => $notes,
|
|
'created_by' => $createdBy,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
}
|