query("SELECT id FROM tenants WHERE status = 'active'")->fetchAll(PDO::FETCH_COLUMN); $gesamtGesendet = 0; $gesamtUebersprungen = 0; foreach ($tenants as $tenantIdRaw) { $tenantId = (int)$tenantIdRaw; $settings = saas_fetch_tenant_settings($pdo, $tenantId); if ($settings === null || (int)$settings['payment_reminder_enabled'] !== 1) { continue; } $schwelleCents = (int)$settings['negative_warning_cents']; // <= 0 $intervallTage = max(1, (int)$settings['payment_reminder_interval_days']); $jetzt = new DateTimeImmutable('now'); $teilnehmer = ledger_fetch_participant_summaries($pdo, $tenantId, ['active_only' => true]); $letzteErinnerungen = saas_fetch_last_payment_reminders($pdo, $tenantId); foreach ($teilnehmer as $person) { $balanceCents = (int)$person['balance_cents']; // Nur echte Schuld oberhalb der Schwelle (balance ist negativ = Schulden). if ($balanceCents >= 0 || $balanceCents > $schwelleCents) { continue; } $email = trim((string)($person['email'] ?? '')); if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { continue; } $participantId = (int)$person['participant_id']; if (isset($letzteErinnerungen[$participantId])) { try { $letzte = new DateTimeImmutable($letzteErinnerungen[$participantId]); if ($letzte->add(new DateInterval("P{$intervallTage}D")) > $jetzt) { $gesamtUebersprungen++; continue; } } catch (Throwable $e) { // Unparsebares Datum: sicherheitshalber ueberspringen. $gesamtUebersprungen++; continue; } } $debtCents = abs($balanceCents); $subject = 'Kaffeeliste - Erinnerung an deinen offenen Betrag'; $body = saas_render_payment_reminder_mail_body((string)$person['display_name'], $debtCents, $settings, $dashboardUrl); if ($dryRun) { echo "[dry-run] Mandant {$tenantId}: {$person['display_name']} <{$email}> offen " . saas_format_money_cents($debtCents) . " EUR\n"; $gesamtGesendet++; continue; } $sendResult = saas_send_mail($email, $subject, $body); saas_log_outbound_email( $pdo, $tenantId, $participantId, 'payment_reminder', $subject, $sendResult['ok'] ? 'sent' : 'failed', $sendResult['error'] ?? null, null ); if ($sendResult['ok']) { $gesamtGesendet++; } } if (!$dryRun) { app_audit_log($pdo, $tenantId, null, 'payment_reminder.batch', 'tenant', $tenantId, ['gesendet' => $gesamtGesendet]); } } echo ($dryRun ? "[dry-run] " : "") . "Fertig: {$gesamtGesendet} Erinnerung(en) " . ($dryRun ? "waeren versendet worden" : "versendet") . ", {$gesamtUebersprungen} wegen Intervall uebersprungen.\n";