Fix Event & EventType resource issues and apply formatting

- Fix EventType deletion error handling (constraint violations)
- Fix Event update error (package_id column missing)
- Fix Event Type dropdown options (JSON display issue)
- Fix EventPackagesRelationManager query error
- Add missing translations for deletion errors
- Apply Pint formatting
This commit is contained in:
Codex Agent
2026-01-21 10:34:06 +01:00
parent 198fbf6751
commit fa33e7cbcf
112 changed files with 334 additions and 280 deletions

View File

@@ -7,7 +7,6 @@ use App\Models\Tenant;
use App\Models\User;
use Illuminate\Console\Attributes\AsCommand;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
#[AsCommand(name: 'tenant:attach-demo-event')]
class AttachDemoEvent extends Command
@@ -25,10 +24,12 @@ class AttachDemoEvent extends Command
{
if (! \Illuminate\Support\Facades\Schema::hasTable('events')) {
$this->error("Table 'events' does not exist. Run: php artisan migrate");
return self::FAILURE;
}
if (! \Illuminate\Support\Facades\Schema::hasColumn('events', 'tenant_id')) {
$this->error("Column 'events.tenant_id' does not exist. Add it and rerun. Suggested: create a migration to add a nullable foreignId to tenants.");
return self::FAILURE;
}
$tenant = null;
@@ -45,6 +46,7 @@ class AttachDemoEvent extends Command
}
if (! $tenant) {
$this->error('Tenant not found. Provide --tenant-slug or a user with tenant_id via --tenant-email.');
return self::FAILURE;
}
@@ -67,12 +69,14 @@ class AttachDemoEvent extends Command
if (! $event) {
$this->error('Event not found. Provide --event-id or --event-slug.');
return self::FAILURE;
}
// Idempotent update
if ((int) $event->tenant_id === (int) $tenant->id) {
$this->info("Event #{$event->id} already attached to tenant #{$tenant->id} ({$tenant->slug}).");
return self::SUCCESS;
}
@@ -80,6 +84,7 @@ class AttachDemoEvent extends Command
$event->save();
$this->info("Attached event #{$event->id} ({$event->slug}) to tenant #{$tenant->id} ({$tenant->slug}).");
return self::SUCCESS;
}
}

View File

@@ -10,22 +10,27 @@ use Illuminate\Support\Facades\Storage;
class BackfillThumbnails extends Command
{
protected $signature = 'media:backfill-thumbnails {--limit=500}';
protected $description = 'Generate thumbnails for photos missing thumbnail_path or where thumbnail equals original.';
public function handle(): int
{
$limit = (int) $this->option('limit');
$rows = DB::table('photos')
->select(['id','event_id','file_path','thumbnail_path'])
->select(['id', 'event_id', 'file_path', 'thumbnail_path'])
->orderBy('id')
->limit($limit)
->get();
$count = 0;
foreach ($rows as $r) {
$orig = $this->relativeFromUrl((string)$r->file_path);
$thumb = (string)($r->thumbnail_path ?? '');
if ($thumb && $thumb !== $r->file_path) continue; // already set to different thumb
if (! $orig) continue;
$orig = $this->relativeFromUrl((string) $r->file_path);
$thumb = (string) ($r->thumbnail_path ?? '');
if ($thumb && $thumb !== $r->file_path) {
continue;
} // already set to different thumb
if (! $orig) {
continue;
}
$baseName = pathinfo($orig, PATHINFO_FILENAME);
$destRel = "events/{$r->event_id}/photos/thumbs/{$baseName}_thumb.jpg";
$made = ImageHelper::makeThumbnailOnDisk('public', $orig, $destRel, 640, 82);
@@ -39,6 +44,7 @@ class BackfillThumbnails extends Command
}
}
$this->info("Done. Thumbnails generated: {$count}");
return self::SUCCESS;
}
@@ -49,6 +55,7 @@ class BackfillThumbnails extends Command
if (str_starts_with($p, '/storage/')) {
return substr($p, strlen('/storage/'));
}
return null;
}
}

View File

@@ -4,15 +4,15 @@ namespace App\Console\Commands;
use App\Models\PackagePurchase;
use App\Models\Tenant;
use App\Models\User;
use App\Models\TenantPackage;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
class MigrateLegacyPurchases extends Command
{
protected $signature = 'packages:migrate-legacy';
protected $description = 'Migrate legacy purchases to new system with temp tenants';
public function handle()
@@ -21,19 +21,20 @@ class MigrateLegacyPurchases extends Command
if ($legacyPurchases->isEmpty()) {
$this->info('No legacy purchases found.');
return 0;
}
$this->info("Found {$legacyPurchases->count()} legacy purchases.");
foreach ($legacyPurchases as $purchase) {
if (!$purchase->user_id) {
if (! $purchase->user_id) {
// Create temp user if no user
$tempUser = User::create([
'name' => 'Legacy User ' . $purchase->id,
'email' => 'legacy' . $purchase->id . '@fotospiel.local',
'name' => 'Legacy User '.$purchase->id,
'email' => 'legacy'.$purchase->id.'@fotospiel.local',
'password' => Hash::make('legacy'),
'username' => 'legacy' . $purchase->id,
'username' => 'legacy'.$purchase->id,
'first_name' => 'Legacy',
'last_name' => 'User',
'address' => 'Legacy Address',
@@ -43,7 +44,7 @@ class MigrateLegacyPurchases extends Command
$tempTenant = Tenant::create([
'user_id' => $tempUser->id,
'name' => 'Legacy Tenant ' . $purchase->id,
'name' => 'Legacy Tenant '.$purchase->id,
'status' => 'active',
]);
@@ -73,6 +74,7 @@ class MigrateLegacyPurchases extends Command
}
$this->info('Legacy migration completed.');
return 0;
}
}
}

View File

@@ -62,7 +62,7 @@ class SendAbandonedCheckoutReminders extends Command
if ($this->shouldSendReminder($checkout, $stage)) {
$resumeUrl = $this->generateResumeUrl($checkout);
if (!$isDryRun) {
if (! $isDryRun) {
$mailLocale = $checkout->user->preferred_locale ?? config('app.locale');
Mail::to($checkout->user)
@@ -86,8 +86,8 @@ class SendAbandonedCheckoutReminders extends Command
$totalProcessed++;
}
} catch (Throwable $e) {
Log::error("Failed to send {$stage} reminder for checkout {$checkout->id}: " . $e->getMessage());
$this->error(" ❌ Failed to process checkout {$checkout->id}: " . $e->getMessage());
Log::error("Failed to send {$stage} reminder for checkout {$checkout->id}: ".$e->getMessage());
$this->error(" ❌ Failed to process checkout {$checkout->id}: ".$e->getMessage());
}
}
}
@@ -98,7 +98,7 @@ class SendAbandonedCheckoutReminders extends Command
->count();
if ($oldCheckouts > 0) {
if (!$isDryRun) {
if (! $isDryRun) {
AbandonedCheckoutModel::where('abandoned_at', '<', now()->subDays(30))
->where('converted', false)
->delete();
@@ -108,10 +108,10 @@ class SendAbandonedCheckoutReminders extends Command
}
}
$this->info("✅ Reminder process completed!");
$this->info('✅ Reminder process completed!');
$this->info(" Processed: {$totalProcessed} checkouts");
if (!$isDryRun) {
if (! $isDryRun) {
$this->info(" Sent: {$totalSent} reminder emails");
} else {
$this->info(" Would send: {$totalSent} reminder emails");
@@ -131,12 +131,12 @@ class SendAbandonedCheckoutReminders extends Command
}
// User existiert noch?
if (!$checkout->user) {
if (! $checkout->user) {
return false;
}
// Package existiert noch?
if (!$checkout->package) {
if (! $checkout->package) {
return false;
}