option('dry-run'); $reminded = 0; $due = Instance::query() ->with('customer') ->where('status', 'cancellation_scheduled') ->whereNotNull('service_ends_at') // In der Zukunft und höchstens sieben Tage entfernt — siehe // Kopfkommentar. Eine bereits abgelaufene Instanz gehört // EndDueServices, nicht mehr dieser Erinnerung. ->where('service_ends_at', '>', now()) ->where('service_ends_at', '<=', now()->addDays(7)) ->whereNull('export_reminded_at') ->cursor(); foreach ($due as $instance) { $customer = $instance->customer; if ($customer === null || blank($customer->email)) { // Laut, aber ohne export_reminded_at zu setzen: eine Mail, die // nie eine Adresse hatte, ist keine, die verschickt wurde. Log::warning('Instanz nähert sich dem Laufzeitende, aber kein erreichbarer Kunde dahinter.', [ 'instance' => $instance->uuid, ]); continue; } $this->line(($dryRun ? '[dry-run] ' : '') ."{$instance->subdomain}: Laufzeit endet am " .$instance->service_ends_at->local()->isoFormat('LL')); if ($dryRun) { $reminded++; continue; } try { $mail = new ServiceEndingSoonMail($instance); Mail::mailer($mail->mailer)->to($customer->email)->queue($mail); } catch (Throwable $e) { Log::warning('Die Erinnerung vor dem Laufzeitende ließ sich nicht einreihen.', [ 'instance' => $instance->uuid, 'exception' => $e->getMessage(), ]); continue; } // Hält fest, dass erinnert wurde — ohne diese Spalte schickte der // tägliche Lauf dieselbe Mail an jedem der restlichen Tage erneut. $instance->update(['export_reminded_at' => now()]); $reminded++; } $this->info($dryRun ? "Probelauf: {$reminded} Erinnerung(en) würden verschickt. Nichts wurde geändert." : "{$reminded} Erinnerung(en) verschickt."); return self::SUCCESS; } }