Erweiterte Bezahloptionen: Barzahlung, PayPal und Ueberweisung

Bisher gab es nur PayPal. Jetzt sind pro Mandant drei unabhaengig
aktivierbare Zahlungswege konfigurierbar (mandant-einstellungen.php):

- Barzahlung mit frei waehlbarem Ansprechpartner.
- PayPal wie bisher, mit Zahlungslink.
- Ueberweisung mit Kontoinhaber und IBAN (Format wird geprueft,
  Leerzeichen werden normalisiert).

Das Mitglieder-Dashboard (index.php) zeigt unter "Bezahlen" alle
aktivierten Methoden mit dem jeweils offenen Betrag; die IBAN wird zur
besseren Lesbarkeit in Viererbloecken angezeigt.

Neue tenant_settings-Spalten via Migration 0021 (cash_enabled,
cash_contact, bank_transfer_enabled, bank_account_holder, bank_iban).
This commit is contained in:
2026-07-21 16:13:28 +02:00
parent bafa5e7e61
commit c16b105f00
4 changed files with 116 additions and 9 deletions
+40 -4
View File
@@ -281,7 +281,12 @@ function saas_fetch_tenant_settings(PDO $pdo, int $tenantId): ?array
ts.pdf_footer_text, ts.pdf_footer_text,
ts.payment_reminder_enabled, ts.payment_reminder_enabled,
ts.payment_reminder_interval_days, ts.payment_reminder_interval_days,
ts.pdf_watermark_logo ts.pdf_watermark_logo,
ts.cash_enabled,
ts.cash_contact,
ts.bank_transfer_enabled,
ts.bank_account_holder,
ts.bank_iban
FROM tenants t FROM tenants t
LEFT JOIN tenant_settings ts ON ts.tenant_id = t.id LEFT JOIN tenant_settings ts ON ts.tenant_id = t.id
WHERE t.id = ? WHERE t.id = ?
@@ -322,6 +327,11 @@ function saas_fetch_tenant_settings(PDO $pdo, int $tenantId): ?array
'payment_reminder_enabled' => (int)$settings['payment_reminder_enabled'], 'payment_reminder_enabled' => (int)$settings['payment_reminder_enabled'],
'payment_reminder_interval_days' => (int)$settings['payment_reminder_interval_days'], 'payment_reminder_interval_days' => (int)$settings['payment_reminder_interval_days'],
'pdf_watermark_logo' => (string)$settings['pdf_watermark_logo'], 'pdf_watermark_logo' => (string)$settings['pdf_watermark_logo'],
'cash_enabled' => (int)$settings['cash_enabled'],
'cash_contact' => (string)$settings['cash_contact'],
'bank_transfer_enabled' => (int)$settings['bank_transfer_enabled'],
'bank_account_holder' => (string)$settings['bank_account_holder'],
'bank_iban' => (string)$settings['bank_iban'],
]; ];
} }
@@ -335,6 +345,9 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
$sheetWindowDays = filter_var($input['sheet_window_days'] ?? null, FILTER_VALIDATE_INT); $sheetWindowDays = filter_var($input['sheet_window_days'] ?? null, FILTER_VALIDATE_INT);
$negativeWarningCents = saas_parse_money_cents($input['negative_warning'] ?? ''); $negativeWarningCents = saas_parse_money_cents($input['negative_warning'] ?? '');
$paypalUrlTemplate = trim((string)($input['paypal_url_template'] ?? '')); $paypalUrlTemplate = trim((string)($input['paypal_url_template'] ?? ''));
$cashContact = trim((string)($input['cash_contact'] ?? ''));
$bankAccountHolder = trim((string)($input['bank_account_holder'] ?? ''));
$bankIban = strtoupper(preg_replace('/\s+/', '', (string)($input['bank_iban'] ?? '')));
$pdfSplitMode = trim((string)($input['pdf_split_mode'] ?? 'drinking_behavior')); $pdfSplitMode = trim((string)($input['pdf_split_mode'] ?? 'drinking_behavior'));
$pdfRowHeightPx = filter_var($input['pdf_row_height_px'] ?? null, FILTER_VALIDATE_INT); $pdfRowHeightPx = filter_var($input['pdf_row_height_px'] ?? null, FILTER_VALIDATE_INT);
$pdfWatermarkText = trim((string)($input['pdf_watermark_text'] ?? '')); $pdfWatermarkText = trim((string)($input['pdf_watermark_text'] ?? ''));
@@ -381,6 +394,15 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
if ($paymentReminderIntervalDays === false || $paymentReminderIntervalDays < 1 || $paymentReminderIntervalDays > 90) { if ($paymentReminderIntervalDays === false || $paymentReminderIntervalDays < 1 || $paymentReminderIntervalDays > 90) {
$errors[] = 'Das Erinnerungs-Intervall muss zwischen 1 und 90 Tagen liegen.'; $errors[] = 'Das Erinnerungs-Intervall muss zwischen 1 und 90 Tagen liegen.';
} }
if (strlen($cashContact) > 255) {
$errors[] = 'Der Bar-Ansprechpartner ist zu lang (max. 255 Zeichen).';
}
if (strlen($bankAccountHolder) > 255) {
$errors[] = 'Der Kontoinhaber ist zu lang (max. 255 Zeichen).';
}
if ($bankIban !== '' && !preg_match('/^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$/', $bankIban)) {
$errors[] = 'Die IBAN hat kein gültiges Format.';
}
if ($errors !== []) { if ($errors !== []) {
return ['ok' => false, 'errors' => $errors]; return ['ok' => false, 'errors' => $errors];
@@ -388,6 +410,8 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
$selfEntryEnabled = !empty($input['self_entry_enabled']) ? 1 : 0; $selfEntryEnabled = !empty($input['self_entry_enabled']) ? 1 : 0;
$paypalEnabled = !empty($input['paypal_enabled']) ? 1 : 0; $paypalEnabled = !empty($input['paypal_enabled']) ? 1 : 0;
$cashEnabled = !empty($input['cash_enabled']) ? 1 : 0;
$bankTransferEnabled = !empty($input['bank_transfer_enabled']) ? 1 : 0;
$pdfShowEmptyRows = !empty($input['pdf_show_empty_rows']) ? 1 : 0; $pdfShowEmptyRows = !empty($input['pdf_show_empty_rows']) ? 1 : 0;
$paymentReminderEnabled = !empty($input['payment_reminder_enabled']) ? 1 : 0; $paymentReminderEnabled = !empty($input['payment_reminder_enabled']) ? 1 : 0;
@@ -407,8 +431,10 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
paypal_url_template, sheet_window_days, negative_warning_cents, paypal_url_template, sheet_window_days, negative_warning_cents,
pdf_show_empty_rows, pdf_split_mode, pdf_row_height_px, pdf_show_empty_rows, pdf_split_mode, pdf_row_height_px,
pdf_watermark_text, pdf_footer_text, pdf_watermark_text, pdf_footer_text,
payment_reminder_enabled, payment_reminder_interval_days) payment_reminder_enabled, payment_reminder_interval_days,
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) cash_enabled, cash_contact, bank_transfer_enabled,
bank_account_holder, bank_iban)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE ON DUPLICATE KEY UPDATE
mark_price_cents = VALUES(mark_price_cents), mark_price_cents = VALUES(mark_price_cents),
self_entry_enabled = VALUES(self_entry_enabled), self_entry_enabled = VALUES(self_entry_enabled),
@@ -422,7 +448,12 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
pdf_watermark_text = VALUES(pdf_watermark_text), 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_enabled = VALUES(payment_reminder_enabled),
payment_reminder_interval_days = VALUES(payment_reminder_interval_days)' payment_reminder_interval_days = VALUES(payment_reminder_interval_days),
cash_enabled = VALUES(cash_enabled),
cash_contact = VALUES(cash_contact),
bank_transfer_enabled = VALUES(bank_transfer_enabled),
bank_account_holder = VALUES(bank_account_holder),
bank_iban = VALUES(bank_iban)'
); );
$stmt->execute([ $stmt->execute([
$tenantId, $tenantId,
@@ -439,6 +470,11 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
$pdfFooterText, $pdfFooterText,
$paymentReminderEnabled, $paymentReminderEnabled,
(int)$paymentReminderIntervalDays, (int)$paymentReminderIntervalDays,
$cashEnabled,
$cashContact,
$bankTransferEnabled,
$bankAccountHolder,
$bankIban,
]); ]);
$pdo->commit(); $pdo->commit();
@@ -0,0 +1,9 @@
-- Erweiterte Bezahloptionen pro Mandant: Barzahlung (mit Ansprechpartner) und
-- Ueberweisung (mit IBAN und Kontoinhaber). PayPal existiert bereits ueber
-- paypal_enabled/paypal_url_template.
ALTER TABLE tenant_settings
ADD COLUMN cash_enabled TINYINT(1) NOT NULL DEFAULT 0 AFTER pdf_watermark_logo,
ADD COLUMN cash_contact VARCHAR(255) NOT NULL DEFAULT '' AFTER cash_enabled,
ADD COLUMN bank_transfer_enabled TINYINT(1) NOT NULL DEFAULT 0 AFTER cash_contact,
ADD COLUMN bank_account_holder VARCHAR(255) NOT NULL DEFAULT '' AFTER bank_transfer_enabled,
ADD COLUMN bank_iban VARCHAR(40) NOT NULL DEFAULT '' AFTER bank_account_holder;
+34 -1
View File
@@ -271,6 +271,10 @@ if ($hasAccess && $participant !== null && $settings !== null) {
$selfEntryEnabled = (int)$settings['self_entry_enabled'] === 1; $selfEntryEnabled = (int)$settings['self_entry_enabled'] === 1;
$paypalEnabled = (int)$settings['paypal_enabled'] === 1 $paypalEnabled = (int)$settings['paypal_enabled'] === 1
&& trim((string)$settings['paypal_url_template']) !== ''; && trim((string)$settings['paypal_url_template']) !== '';
$cashEnabled = (int)$settings['cash_enabled'] === 1;
$bankTransferEnabled = (int)$settings['bank_transfer_enabled'] === 1
&& trim((string)$settings['bank_iban']) !== '';
$anyPaymentEnabled = $paypalEnabled || $cashEnabled || $bankTransferEnabled;
?> ?>
<h2>Kaffeeliste</h2> <h2>Kaffeeliste</h2>
<?php if ($currentName !== ''): ?> <?php if ($currentName !== ''): ?>
@@ -354,8 +358,37 @@ if ($hasAccess && $participant !== null && $settings !== null) {
<small>Falsch getippt? Mit „Letzten Strich stornieren" nimmst du deinen jüngsten selbst eingetragenen Strich wieder zurück. Vom Kassenwart eingetragene Striche bleiben davon unberührt.</small> <small>Falsch getippt? Mit „Letzten Strich stornieren" nimmst du deinen jüngsten selbst eingetragenen Strich wieder zurück. Vom Kassenwart eingetragene Striche bleiben davon unberührt.</small>
<?php endif; ?> <?php endif; ?>
<?php if ($anyPaymentEnabled): ?>
<h2>Bezahlen</h2>
<?php if ($balanceCents < 0): ?>
<p>Dein offener Betrag: <b><?php echo saas_html(dashboard_money(abs($balanceCents))); ?></b></p>
<?php endif; ?>
<?php endif; ?>
<?php if ($cashEnabled): ?>
<h4>Barzahlung</h4>
<?php if (trim((string)$settings['cash_contact']) !== ''): ?>
<p>Bitte bar bei <b><?php echo saas_html($settings['cash_contact']); ?></b> bezahlen.</p>
<?php else: ?>
<p>Barzahlung ist möglich.</p>
<?php endif; ?>
<?php endif; ?>
<?php if ($bankTransferEnabled): ?>
<h4>Überweisung</h4>
<p>
<?php if (trim((string)$settings['bank_account_holder']) !== ''): ?>
Kontoinhaber: <b><?php echo saas_html($settings['bank_account_holder']); ?></b><br>
<?php endif; ?>
IBAN: <b><?php echo saas_html(trim(chunk_split((string)$settings['bank_iban'], 4, ' '))); ?></b>
<?php if ($balanceCents < 0): ?>
<br>Bitte überweise deinen offenen Betrag von <b><?php echo saas_html(dashboard_money(abs($balanceCents))); ?></b>.
<?php endif; ?>
</p>
<?php endif; ?>
<?php if ($paypalEnabled): ?> <?php if ($paypalEnabled): ?>
<h2>PayPal-Einzahlungen</h2> <h4>PayPal</h4>
<b>Bezahle immer über die Freunde-Funktion von PayPal. Ansonsten stellen wir 20% des Betrags als Gebühr in Rechnung.</b><br> <b>Bezahle immer über die Freunde-Funktion von PayPal. Ansonsten stellen wir 20% des Betrags als Gebühr in Rechnung.</b><br>
<br> <br>
<?php <?php
+33 -4
View File
@@ -45,6 +45,11 @@ if ($canManageSettings) {
'self_entry_enabled' => !empty($_POST['self_entry_enabled']) ? 1 : 0, 'self_entry_enabled' => !empty($_POST['self_entry_enabled']) ? 1 : 0,
'paypal_enabled' => !empty($_POST['paypal_enabled']) ? 1 : 0, 'paypal_enabled' => !empty($_POST['paypal_enabled']) ? 1 : 0,
'paypal_url_template' => $_POST['paypal_url_template'] ?? '', 'paypal_url_template' => $_POST['paypal_url_template'] ?? '',
'cash_enabled' => !empty($_POST['cash_enabled']) ? 1 : 0,
'cash_contact' => $_POST['cash_contact'] ?? '',
'bank_transfer_enabled' => !empty($_POST['bank_transfer_enabled']) ? 1 : 0,
'bank_account_holder' => $_POST['bank_account_holder'] ?? '',
'bank_iban' => $_POST['bank_iban'] ?? '',
'sheet_window_days' => $_POST['sheet_window_days'] ?? 100, 'sheet_window_days' => $_POST['sheet_window_days'] ?? 100,
'negative_warning_cents' => -abs(saas_parse_money_cents($_POST['negative_warning'] ?? '') ?? 0), 'negative_warning_cents' => -abs(saas_parse_money_cents($_POST['negative_warning'] ?? '') ?? 0),
'pdf_show_empty_rows' => !empty($_POST['pdf_show_empty_rows']) ? 1 : 0, 'pdf_show_empty_rows' => !empty($_POST['pdf_show_empty_rows']) ? 1 : 0,
@@ -125,16 +130,40 @@ include 'nav.php';
<input type="text" name="negative_warning" id="negative_warning" value="<?php echo saas_html(saas_format_money_cents(abs((int)$settings['negative_warning_cents']))); ?>" required> <input type="text" name="negative_warning" id="negative_warning" value="<?php echo saas_html(saas_format_money_cents(abs((int)$settings['negative_warning_cents']))); ?>" required>
</div> </div>
<div class="col-12"> <div class="col-12">
<h3>Bezahloptionen</h3>
<p>Aktiviere die Zahlungswege, die deine Mitglieder nutzen können. Nur aktivierte Optionen werden im Mitglieder-Dashboard angezeigt.</p>
</div>
<div class="col-6 col-12-small">
<input type="checkbox" id="cash_enabled" name="cash_enabled" value="1" <?php echo (int)$settings['cash_enabled'] === 1 ? 'checked' : ''; ?>>
<label for="cash_enabled">Barzahlung anbieten</label>
</div>
<div class="col-6 col-12-small">
<label for="cash_contact">Ansprechpartner für Barzahlung</label>
<input type="text" name="cash_contact" id="cash_contact" maxlength="255" value="<?php echo saas_html($settings['cash_contact']); ?>">
</div>
<div class="col-6 col-12-small">
<input type="checkbox" id="paypal_enabled" name="paypal_enabled" value="1" <?php echo (int)$settings['paypal_enabled'] === 1 ? 'checked' : ''; ?>>
<label for="paypal_enabled">PayPal anbieten</label>
</div>
<div class="col-6 col-12-small">
<label for="paypal_url_template">PayPal-Link</label> <label for="paypal_url_template">PayPal-Link</label>
<input type="text" name="paypal_url_template" id="paypal_url_template" value="<?php echo saas_html($settings['paypal_url_template']); ?>"> <input type="text" name="paypal_url_template" id="paypal_url_template" value="<?php echo saas_html($settings['paypal_url_template']); ?>">
</div> </div>
<div class="col-6 col-12-small"> <div class="col-6 col-12-small">
<input type="checkbox" id="self_entry_enabled" name="self_entry_enabled" value="1" <?php echo (int)$settings['self_entry_enabled'] === 1 ? 'checked' : ''; ?>> <input type="checkbox" id="bank_transfer_enabled" name="bank_transfer_enabled" value="1" <?php echo (int)$settings['bank_transfer_enabled'] === 1 ? 'checked' : ''; ?>>
<label for="self_entry_enabled">Web-Striche erlauben</label> <label for="bank_transfer_enabled">Überweisung anbieten</label>
</div> </div>
<div class="col-6 col-12-small"> <div class="col-6 col-12-small">
<input type="checkbox" id="paypal_enabled" name="paypal_enabled" value="1" <?php echo (int)$settings['paypal_enabled'] === 1 ? 'checked' : ''; ?>> <label for="bank_account_holder">Kontoinhaber (Überweisung)</label>
<label for="paypal_enabled">PayPal anzeigen</label> <input type="text" name="bank_account_holder" id="bank_account_holder" maxlength="255" value="<?php echo saas_html($settings['bank_account_holder']); ?>">
</div>
<div class="col-12">
<label for="bank_iban">IBAN (Überweisung)</label>
<input type="text" name="bank_iban" id="bank_iban" maxlength="40" value="<?php echo saas_html($settings['bank_iban']); ?>">
</div>
<div class="col-6 col-12-small">
<input type="checkbox" id="self_entry_enabled" name="self_entry_enabled" value="1" <?php echo (int)$settings['self_entry_enabled'] === 1 ? 'checked' : ''; ?>>
<label for="self_entry_enabled">Web-Striche erlauben</label>
</div> </div>
<div class="col-6 col-12-small"> <div class="col-6 col-12-small">
<input type="checkbox" id="pdf_show_empty_rows" name="pdf_show_empty_rows" value="1" <?php echo (int)$settings['pdf_show_empty_rows'] === 1 ? 'checked' : ''; ?>> <input type="checkbox" id="pdf_show_empty_rows" name="pdf_show_empty_rows" value="1" <?php echo (int)$settings['pdf_show_empty_rows'] === 1 ? 'checked' : ''; ?>>