Sicherheits-/Korrektheits-Fixes und neue Funktionen
Bugfixes aus dem Code-Review: - XSS: unescaptes $_SERVER['PHP_SELF'] in csvupload.php und letzteneintraege.php durch feste Seitennamen ersetzt. - Stripe-Webhook: Event-Deduplizierung (neue Tabelle stripe_webhook_events) gegen doppelte Verarbeitung/Dolibarr-Rechnungen bei Retry-Zustellung. - Stripe-Webhook: Tarifwechsel aus dem Kundenportal wird lokal nachgezogen (plan_code aus dem Preis-lookup_key bei subscription.updated). - Post-Redirect-Get fuer jahresauswertung, mailversenden und die Selbst-Stricheintragung - verhindert Doppelbuchung/Doppelversand per Browser-Refresh. - Jahresbonus: Mails erst nach erfolgreichem Commit; Restcent-Ausgleich beim letzten Empfaenger, damit die Summe exakt stimmt. - Verschachtelte HTML-Dokumente in csvupload/einzahlung/stricheintragen entfernt (Layout kommt aus header.php). - Rate-Limit fuer den Versand von E-Mail-Verifizierungslinks. Neue Funktionen: - Mitglieder koennen ihren zuletzt selbst eingetragenen Strich wieder stornieren (nur eigene Web-Eintraege, Kassenwart-Eintraege bleiben). - Monatsuebersicht des eigenen Verbrauchs im Mitglieder-Dashboard. - Automatische Zahlungserinnerung: opt-in pro Mandant ab der Warnschwelle, mit Intervall; Cron-Skript scripts/send-payment-reminders.php. - CSV-Import fuer Mitgliederlisten inkl. herunterladbarer Vorlage (mitglieder-vorlage.php), Semikolon-/Komma- und BOM-Erkennung. - Logo als PDF-Wasserzeichen pro Mandant (Upload in den Mandant- Einstellungen, geschuetzt unter var/tenant_logos/, ersetzt den Text-Wasserzeichen im Ausdruck). Robusterer Teilnehmer-Lookup im Dashboard ueber user_id (Fallback E-Mail).
This commit is contained in:
+20
-4
@@ -278,7 +278,10 @@ function saas_fetch_tenant_settings(PDO $pdo, int $tenantId): ?array
|
||||
ts.pdf_split_mode,
|
||||
ts.pdf_row_height_px,
|
||||
ts.pdf_watermark_text,
|
||||
ts.pdf_footer_text
|
||||
ts.pdf_footer_text,
|
||||
ts.payment_reminder_enabled,
|
||||
ts.payment_reminder_interval_days,
|
||||
ts.pdf_watermark_logo
|
||||
FROM tenants t
|
||||
LEFT JOIN tenant_settings ts ON ts.tenant_id = t.id
|
||||
WHERE t.id = ?
|
||||
@@ -316,6 +319,9 @@ function saas_fetch_tenant_settings(PDO $pdo, int $tenantId): ?array
|
||||
'pdf_row_height_px' => (int)$settings['pdf_row_height_px'],
|
||||
'pdf_watermark_text' => (string)$settings['pdf_watermark_text'],
|
||||
'pdf_footer_text' => (string)$settings['pdf_footer_text'],
|
||||
'payment_reminder_enabled' => (int)$settings['payment_reminder_enabled'],
|
||||
'payment_reminder_interval_days' => (int)$settings['payment_reminder_interval_days'],
|
||||
'pdf_watermark_logo' => (string)$settings['pdf_watermark_logo'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -333,6 +339,7 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
|
||||
$pdfRowHeightPx = filter_var($input['pdf_row_height_px'] ?? null, FILTER_VALIDATE_INT);
|
||||
$pdfWatermarkText = trim((string)($input['pdf_watermark_text'] ?? ''));
|
||||
$pdfFooterText = trim((string)($input['pdf_footer_text'] ?? ''));
|
||||
$paymentReminderIntervalDays = filter_var($input['payment_reminder_interval_days'] ?? null, FILTER_VALIDATE_INT);
|
||||
|
||||
$errors = [];
|
||||
if (strlen($tenantName) < 3 || strlen($tenantName) > 255) {
|
||||
@@ -371,6 +378,9 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
|
||||
if ($pdfRowHeightPx === false || $pdfRowHeightPx < 10 || $pdfRowHeightPx > 60) {
|
||||
$errors[] = 'Die Zeilenhöhe im Ausdruck muss zwischen 10 und 60 Pixel liegen.';
|
||||
}
|
||||
if ($paymentReminderIntervalDays === false || $paymentReminderIntervalDays < 1 || $paymentReminderIntervalDays > 90) {
|
||||
$errors[] = 'Das Erinnerungs-Intervall muss zwischen 1 und 90 Tagen liegen.';
|
||||
}
|
||||
|
||||
if ($errors !== []) {
|
||||
return ['ok' => false, 'errors' => $errors];
|
||||
@@ -379,6 +389,7 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
|
||||
$selfEntryEnabled = !empty($input['self_entry_enabled']) ? 1 : 0;
|
||||
$paypalEnabled = !empty($input['paypal_enabled']) ? 1 : 0;
|
||||
$pdfShowEmptyRows = !empty($input['pdf_show_empty_rows']) ? 1 : 0;
|
||||
$paymentReminderEnabled = !empty($input['payment_reminder_enabled']) ? 1 : 0;
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
@@ -395,8 +406,9 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
|
||||
(tenant_id, mark_price_cents, self_entry_enabled, paypal_enabled,
|
||||
paypal_url_template, sheet_window_days, negative_warning_cents,
|
||||
pdf_show_empty_rows, pdf_split_mode, pdf_row_height_px,
|
||||
pdf_watermark_text, pdf_footer_text)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
pdf_watermark_text, pdf_footer_text,
|
||||
payment_reminder_enabled, payment_reminder_interval_days)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
mark_price_cents = VALUES(mark_price_cents),
|
||||
self_entry_enabled = VALUES(self_entry_enabled),
|
||||
@@ -408,7 +420,9 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
|
||||
pdf_split_mode = VALUES(pdf_split_mode),
|
||||
pdf_row_height_px = VALUES(pdf_row_height_px),
|
||||
pdf_watermark_text = VALUES(pdf_watermark_text),
|
||||
pdf_footer_text = VALUES(pdf_footer_text)'
|
||||
pdf_footer_text = VALUES(pdf_footer_text),
|
||||
payment_reminder_enabled = VALUES(payment_reminder_enabled),
|
||||
payment_reminder_interval_days = VALUES(payment_reminder_interval_days)'
|
||||
);
|
||||
$stmt->execute([
|
||||
$tenantId,
|
||||
@@ -423,6 +437,8 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
|
||||
(int)$pdfRowHeightPx,
|
||||
$pdfWatermarkText,
|
||||
$pdfFooterText,
|
||||
$paymentReminderEnabled,
|
||||
(int)$paymentReminderIntervalDays,
|
||||
]);
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
Reference in New Issue
Block a user