option('dry-run'); if ($isDryRun) { $this->info('🔍 DRY RUN MODE - No emails will be sent'); } $this->info('🚀 Starting abandoned checkout reminder process...'); // Reminder-Stufen definieren: [Stufe, Stunden, Beschreibung] $reminderStages = [ ['1h', 1, '1 hour reminders'], ['24h', 24, '24 hour reminders'], ['1w', 168, '1 week reminders'], // 7 * 24 = 168 Stunden ]; $totalProcessed = 0; $totalSent = 0; foreach ($reminderStages as [$stage, $hours, $description]) { $this->info("📧 Processing {$description}..."); $checkouts = AbandonedCheckoutModel::readyForReminder($stage, $hours) ->with(['user', 'package']) ->get(); $this->info(" Found {$checkouts->count()} checkouts ready for {$stage} reminder"); foreach ($checkouts as $checkout) { try { if ($this->shouldSendReminder($checkout, $stage)) { $resumeUrl = $this->generateResumeUrl($checkout); if (!$isDryRun) { Mail::to($checkout->user)->queue( new AbandonedCheckout( $checkout->user, $checkout->package, $stage, $resumeUrl ) ); $checkout->updateReminderStage($stage); $totalSent++; } else { $this->line(" 📧 Would send {$stage} reminder to: {$checkout->email} for package: {$checkout->package->name}"); } $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()); } } } // Cleanup: Alte Checkouts löschen (älter als 30 Tage) $oldCheckouts = AbandonedCheckoutModel::where('abandoned_at', '<', now()->subDays(30)) ->where('converted', false) ->count(); if ($oldCheckouts > 0) { if (!$isDryRun) { AbandonedCheckoutModel::where('abandoned_at', '<', now()->subDays(30)) ->where('converted', false) ->delete(); $this->info("🧹 Cleaned up {$oldCheckouts} old abandoned checkouts"); } else { $this->info("🧹 Would clean up {$oldCheckouts} old abandoned checkouts"); } } $this->info("✅ Reminder process completed!"); $this->info(" Processed: {$totalProcessed} checkouts"); if (!$isDryRun) { $this->info(" Sent: {$totalSent} reminder emails"); } else { $this->info(" Would send: {$totalSent} reminder emails"); } return Command::SUCCESS; } /** * Prüft ob ein Reminder versendet werden sollte */ private function shouldSendReminder(AbandonedCheckoutModel $checkout, string $stage): bool { // Verfällt der Checkout bald? Dann kein Reminder mehr if ($checkout->isExpired()) { return false; } // User existiert noch? if (!$checkout->user) { return false; } // Package existiert noch? if (!$checkout->package) { return false; } return true; } /** * Generiert die URL zum Wiederaufnehmen des Checkouts */ private function generateResumeUrl(AbandonedCheckoutModel $checkout): string { // Für jetzt: Einfache Package-URL // Später: Persönliche Resume-Token URLs return route('buy.packages', $checkout->package_id); } }