presseportale/app/Console/Commands/MigrateLegacyAgencyNames.php
Kevin Adametz 402fa4a38b legacy:migrate-agency-names: Agentur-Namen → users.agency_name
Übernimmt je Owner den Namen seiner Legacy-Agentur-Firma(en) ins neue
Profilfeld (A2 des Umbaus Agentur-Attribution → User-Profil). Regeln:
zuletzt aktualisierter Datensatz gewinnt bei Mehrfach-Namen (alle
Varianten im Report), bereits gesetzte Werte werden nie überschrieben,
Owner-lose Agentur-Firmen werden nur reportet. --dry-run + JSON-Report
nach storage/app/private/migration/; im Deploy-Runbook (Erst-Einrichtung)
nach dem Firmen-/User-Import eingereiht.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 09:25:04 +00:00

131 lines
4.6 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Enums\CompanyType;
use App\Models\Company;
use App\Models\User;
use App\Scopes\PortalScope;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
/**
* Übernimmt die Namen der Legacy-Agentur-Firmen (companies.type = agency)
* in das Profilfeld users.agency_name des jeweiligen Owners — Teil des
* Umbaus Agentur-Attribution → User-Profil (dev/agentur-attribution/
* entwicklungsplan.md, A2). Läuft im Go-Live NACH dem Firmen-/User-Import
* und VOR companies:retire-agency-type. Wiederholbar: bereits gesetzte
* agency_name-Werte werden nie überschrieben.
*
* Verwendung:
* php artisan legacy:migrate-agency-names --dry-run
* php artisan legacy:migrate-agency-names
*/
class MigrateLegacyAgencyNames extends Command
{
protected $signature = 'legacy:migrate-agency-names
{--dry-run : Nur anzeigen und Report schreiben, keine User ändern}';
protected $description = 'Übernimmt Namen der Legacy-Agentur-Firmen in das Profilfeld users.agency_name.';
public function handle(): int
{
$dryRun = (bool) $this->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;
}
}