option('dry-run'); if ($dryRun) { $this->warn('[DRY-RUN] Kein tatsächlicher Schreibvorgang.'); } // Bewusst ohne is_active-Filter: die Attributions-Zeile hat auch // inaktive Agentur-Firmen angezeigt; dieses Verhalten bleibt erhalten. $agencies = Company::withoutGlobalScope(PortalScope::class) ->where('type', CompanyType::Agency) ->get(['id', 'portal', 'owner_user_id', 'name', 'is_active', 'updated_at']); $report = [ 'generated_at' => now()->toIso8601String(), 'dry_run' => $dryRun, 'summary' => [], 'multiple_names' => [], 'skipped_existing' => [], 'ownerless' => [], 'missing_owner' => [], ]; foreach ($agencies->whereNull('owner_user_id') as $orphan) { $report['ownerless'][] = [ 'company_id' => $orphan->id, 'portal' => $orphan->portal?->value, 'name' => $orphan->name, ]; } $byOwner = $agencies->whereNotNull('owner_user_id')->groupBy('owner_user_id'); $users = User::withTrashed()->whereIn('id', $byOwner->keys())->get()->keyBy('id'); $migrated = 0; foreach ($byOwner as $userId => $companies) { $user = $users->get($userId); if ($user === null) { $report['missing_owner'][] = [ 'user_id' => $userId, 'company_ids' => $companies->pluck('id')->all(), ]; continue; } /** @var Company $winner Zuletzt aktualisierter Datensatz gewinnt (Regel Mehrfach-Fälle). */ $winner = $companies->sortByDesc('updated_at')->first(); $variants = $companies->pluck('name')->unique()->values(); if ($variants->count() > 1) { $report['multiple_names'][] = [ 'user_id' => $user->id, 'email' => $user->email, 'chosen' => $winner->name, 'variants' => $variants->all(), ]; } if (filled($user->agency_name)) { $report['skipped_existing'][] = [ 'user_id' => $user->id, 'email' => $user->email, 'existing' => $user->agency_name, 'candidate' => $winner->name, ]; continue; } if (! $dryRun) { $user->update(['agency_name' => $winner->name]); } $migrated++; } $report['summary'] = [ 'agency_companies' => $agencies->count(), 'users_migrated' => $migrated, 'users_skipped_existing' => count($report['skipped_existing']), 'users_multiple_names' => count($report['multiple_names']), 'companies_ownerless' => count($report['ownerless']), 'owners_missing' => count($report['missing_owner']), ]; $this->table( ['Agentur-Firmen', 'User migriert', 'Bereits gesetzt', 'Mehrfach-Namen', 'Ohne Owner', 'Owner fehlt'], [array_values($report['summary'])], ); $path = 'migration/agency-names-'.now()->format('Ymd-His').'.json'; Storage::disk('local')->put($path, json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); $this->line("Report geschrieben: storage/app/private/{$path}"); return self::SUCCESS; } }