Betreiber-Zentralstelle, Mandanten-Design und schlankerer Einstieg

Funktions-Schalter je Mandant (app/features.php, tenant_features): der
Betreiber schaltet FAQ, Selbsteintrag, PDF, PayPal-Eingang, CSV-Import,
Mailversand, Jahresabschluss, Datenexport und eigenes Design pro Mandant
frei. Gesperrte Funktionen verschwinden aus Menue und Schaltflaechen, ihre
Seiten weisen Aufrufe und POSTs ab. Das Back-Office ist jetzt fuer
Platform-Admins im Menue verlinkt statt nur per URL erreichbar.

Eigenes Design je Mandant: Akzentfarbe und Logo in den Mandant-
Einstellungen, eingebettet ueber app/branding.php; das Logo liegt
geschuetzt in var/tenant_logos und wird nur ueber
tenant-logo-anzeigen.php an den eigenen Mandanten ausgeliefert.

Weniger Startinformationen: Startpaket neuer Mandanten auf zwei
Beispielfragen gekuerzt, Anleitung von ~1400 auf ~750 Woerter gestrafft
und um Abschnitte zu gesperrten Funktionen bereinigt.

Vorder-/Rueckseite erst bei mehr als 50 Personen (vorher schon ab 50).
Die Schwelle liegt jetzt gemeinsam in app/ledger.php und gilt auch fuer
die Vorder-/Rueckseiten-Auswahl beim Erfassen, wo sie bisher unabhaengig
von der Teamgroesse angeboten wurde.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 22:52:55 +02:00
co-authored by Claude Opus 5
parent a93e067e04
commit d24ee9bf91
30 changed files with 881 additions and 172 deletions
+81 -133
View File
@@ -2,6 +2,7 @@
include "functions.php";
require_once __DIR__ . "/app/ledger.php";
require_once __DIR__ . "/app/features.php";
$pdo = app_db_pdo();
$saasUser = saas_current_user($pdo);
@@ -16,6 +17,13 @@ $istAdmin = $saasUser !== null && saas_user_has_role(['owner', 'admin'], $saasUs
// Einstellungen fuer die Hinweise zu den aktivierten Zahlungswegen.
$settings = $saasUser !== null ? saas_fetch_tenant_settings($pdo, (int)$saasUser['tenant_id']) : null;
// Gleiche Logik wie im Menue: was der Betreiber fuer diesen Mandanten
// gesperrt hat, wird hier auch nicht erklaert.
$anleitungTenantId = $saasUser !== null ? (int)$saasUser['tenant_id'] : 0;
$kann = static function (string $feature) use ($pdo, $anleitungTenantId): bool {
return $anleitungTenantId <= 0 || app_feature_enabled($pdo, $anleitungTenantId, $feature);
};
include "header.php";
include "headerline.php";
include "nav.php";
@@ -25,8 +33,8 @@ include "nav.php";
<div class="content">
<h2>Anleitung</h2>
<p>Diese Seite erklärt die wichtigsten Funktionen der Kaffeeliste. Oben stehen
die Punkte, die jedes Mitglied betreffen, darunter die Verwaltungsfunktionen.</p>
<p>Kurzüberblick über die Funktionen. Oben steht, was jedes Mitglied betrifft,
darunter die Verwaltung.</p>
<?php if ($saasUser === null): ?>
<div class="hint-box">
@@ -40,34 +48,20 @@ include "nav.php";
<h2>Für alle Mitglieder</h2>
<h3>Meine Kaffeeliste</h3>
<p>Das ist deine Startseite. Sie zeigt deinen <b>aktuellen Stand</b>, deine
Jahresübersicht sowie die letzten Einzahlungen und Striche.</p>
<ul>
<li><b>Guthaben</b> (positiver Betrag): Du hast mehr eingezahlt, als du verbraucht hast.</li>
<li><b>Schulden</b> (negativer Betrag): Es ist Zeit für eine Einzahlung.</li>
</ul>
<p>In der <b>Monatsübersicht</b> siehst du, wie viele Striche in welchem Monat
zusammengekommen sind.</p>
<p>Deine Startseite zeigt den aktuellen Stand, die Jahres- und Monatsübersicht sowie
die letzten Buchungen. Positiver Betrag = Guthaben, negativer Betrag = offener Betrag.</p>
<?php if ($kann('self_entry')): ?>
<h3>Striche selbst eintragen</h3>
<p>Wenn die Verwaltung das freigeschaltet hat, kannst du deinen Kaffee direkt auf
der Startseite eintragen ein oder zwei Striche pro Vorgang.</p>
<div class="hint-box">
<p><b>Vertippt?</b> Direkt darunter kannst du deinen <b>zuletzt selbst
eingetragenen</b> Strich wieder stornieren. Striche, die der Kassenwart über die
Sammelerfassung eingetragen hat, kannst du nicht selbst stornieren wende dich
dafür an die Verwaltung.</p>
</div>
<p>Wenn die Verwaltung das freigeschaltet hat, trägst du deinen Kaffee direkt auf der
Startseite ein. Vertippt? Mit „Letzten Strich stornieren" nimmst du deinen jüngsten
<b>selbst</b> eingetragenen Strich zurück vom Kassenwart erfasste Striche nicht.</p>
<?php endif; ?>
<h3>Bezahlen</h3>
<p>Welche Wege zur Verfügung stehen, legt die Verwaltung fest. Möglich sind:</p>
<ul>
<li><b>Barzahlung</b> beim angegebenen Ansprechpartner.</li>
<li><b>PayPal</b> über die Schaltflächen auf der Startseite.</li>
<li><b>Überweisung</b> auf die angegebene IBAN.</li>
</ul>
<p>Welche Wege offen stehen, legt die Verwaltung fest: Barzahlung, PayPal oder Überweisung.</p>
<?php if ($settings !== null): ?>
<p><small>In eurem Mandanten sind aktuell aktiv:
<p><small>Bei euch aktiv:
<?php
$wege = [];
if ((int)$settings['cash_enabled'] === 1) { $wege[] = 'Barzahlung'; }
@@ -77,148 +71,103 @@ include "nav.php";
?>.</small></p>
<?php endif; ?>
<div class="hint-box">
<p><b>Wichtig bei PayPal:</b> Nutzt die Funktion „Geld an Freunde senden“. Bei
Zahlungen für „Waren und Dienstleistungen zieht PayPal Gebühren ab gutgeschrieben
wird dann nur der Betrag, der tatsächlich angekommen ist.</p>
<p><b>Wichtig bei PayPal:</b> „Geld an Freunde senden" nutzen. Bei „Waren und
Dienstleistungen" zieht PayPal Gebühren ab gutgeschrieben wird nur, was ankommt.</p>
</div>
<h3>Anzeigenamen ändern</h3>
<p>Unter <b>Namensanpassung</b> kannst du festlegen, wie dein Name auf der
Kaffeeliste und im Ausdruck erscheint (maximal 20 Zeichen).</p>
<h3>Kundenkonto</h3>
<p>Unter <b>Kundenkonto</b> findest du deine Zugangsdaten, kannst deine E-Mail-Adresse
bestätigen und dein Passwort ändern.</p>
<h3>Eigene Angaben</h3>
<p>Unter <b>Namensanpassung</b> legst du fest, wie dein Name in der Liste und im Ausdruck
erscheint (max. 20 Zeichen). Unter <b>Kundenkonto</b> änderst du Passwort und E-Mail.</p>
<?php if ($istKassenwart): ?>
<hr>
<h2>Für Kassenwart und Verwaltung</h2>
<p><small>Sichtbar für die Rollen <b>Kassenwart</b>, <b>Administrator</b> und
<b>Inhaber</b>.</small></p>
<h3>Einzahlung eintragen</h3>
<p>Trage hier ein, wer wie viel eingezahlt hat. Du kannst mehrere Mitglieder in
einem Durchgang erfassen; leere Felder werden übersprungen.</p>
<h3>Buchen</h3>
<ul>
<li><b>Bemerkung</b>: optionale Notiz, damit später nachvollziehbar bleibt, worum es ging.</li>
<li><b>Negativer Betrag</b> = Abzug (z.&nbsp;B. Auszahlung bei Austritt oder eine
Erstattung). Dabei ist eine Bemerkung <b>Pflicht</b>.</li>
<li><b>Einzahlung eintragen</b>: mehrere Mitglieder in einem Durchgang; leere Felder
werden übersprungen. Negativer Betrag = Abzug, dann ist eine Bemerkung Pflicht.</li>
<li><b>Striche eintragen</b>: Sammelerfassung für die Papierliste. Der Preis pro Strich
kommt aus den Einstellungen und ist pro Vorgang überschreibbar.</li>
<li><b>Letzte Einträge</b>: falsche Buchungen hier <b>stornieren</b>, nicht per
Gegenbuchung ausgleichen sonst zählen beide als Umsatz in der Auswertung.</li>
</ul>
<div class="hint-box">
<p><b>Falsch eingetragen ist kein Abzug.</b> Wenn eine Buchung schlicht falsch war,
storniere sie unter <b>Letzte Einträge</b>. Ein Gegen-Abzug würde die Auswertung
verfälschen, weil dann beide Buchungen als Umsatz zählen.</p>
<p>Zum Schutz vor Vertippern werden Beträge über 1.000&nbsp;€ abgelehnt. Schlägt eine
Zeile fehl, wird <b>nichts</b> gebucht und deine Eingaben bleiben stehen.</p>
</div>
<h3>Striche eintragen</h3>
<p>Sammelerfassung für die Papierliste. Über die Schaltflächen wählst du:</p>
<ul>
<li><b>Vorderseite</b>: Vieltrinker Mitglieder mit mindestens 10 Strichen im Listenfenster.</li>
<li><b>Rückseite</b>: alle übrigen aktiven Mitglieder.</li>
<li><b>Alle</b>: die komplette Liste.</li>
</ul>
<p>Der <b>Preis pro Strich</b> wird aus den Mandant-Einstellungen vorbelegt und kann
für den einzelnen Vorgang überschrieben werden.</p>
<h3>Letzte Einträge stornieren</h3>
<p>Zeigt die letzten 100 Einzahlungen und Striche. Fehlerhafte Buchungen werden
<b>storniert</b>, nicht gelöscht: Sie verschwinden aus der Auswertung, bleiben aber
im Journal nachvollziehbar.</p>
<?php if ($kann('paypal_inbox')): ?>
<h3>PayPal-Zahlungen automatisch verbuchen</h3>
<p>Die Kaffeeliste kann PayPal-Zahlungen selbstständig gutschreiben:</p>
<ol>
<li>Auf der Seite <b>PayPal-Zahlungen</b> steht eure persönliche Eingangsadresse.</li>
<li>Richtet in eurem Mailprogramm eine <b>automatische Weiterleitung</b> der
PayPal-Benachrichtigungen an diese Adresse ein.</li>
<li>Erkannte Zahlungen werden dem passenden Mitglied automatisch gutgeschrieben.</li>
</ol>
<p>Gutgeschrieben wird immer der Betrag, der <b>tatsächlich angekommen</b> ist bei
Waren&nbsp;&amp;&nbsp;Dienstleistungen also nach Abzug der PayPal-Gebühr.</p>
<div class="hint-box">
<p>Zahlungen, die sich nicht eindeutig zuordnen lassen, landen in der Warteschlange
„Offene Zahlungen“ und können dort von Hand einem Mitglied zugeordnet oder ignoriert
werden. Damit die automatische Zuordnung möglichst oft greift, hinterlege den
<b>PayPal-Namen</b> beim Mitglied.</p>
</div>
<p>Auf der Seite <b>PayPal-Zahlungen</b> steht eure Eingangsadresse. Leitet die
PayPal-Benachrichtigungen aus eurem Postfach automatisch dorthin weiter, dann werden
erkannte Zahlungen selbstständig gutgeschrieben immer der tatsächlich angekommene
Betrag. Nicht eindeutig zuordenbare Zahlungen landen in der Warteschlange „Offene
Zahlungen". Ein hinterlegter <b>PayPal-Name</b> beim Mitglied verbessert die Trefferquote.</p>
<?php endif; ?>
<h3>CSV-Import</h3>
<p>Über <b>CSV Upload</b> lassen sich Einzahlungen aus einer Datei einlesen. Der Import
zeigt zuerst eine <b>Vorschau</b>; erst danach wird gebucht. Zeilen ohne eindeutige
Zuordnung werden markiert und nicht verbucht.</p>
<h3>Kaffeeliste, Ausdruck und Auswertung</h3>
<h3>Auswertung und Ausdruck</h3>
<ul>
<li><b>Kaffeeliste anzeigen</b>: Gesamtübersicht aller aktiven Mitglieder. Ein Klick
auf den Namen öffnet die Einzelauswertung.</li>
<li><b>PDF-Export</b>: die Liste zum Ausdrucken und Aufhängen.</li>
<li><b>Journal-Vorschau</b>: alle Buchungen mit Herkunft nützlich zur Kontrolle.</li>
<li><b>Kaffeeliste anzeigen</b>: Gesamtübersicht; ein Klick auf den Namen öffnet die
Einzelauswertung.</li>
<?php if ($kann('pdf_export')): ?>
<li><b>PDF-Export</b>: die Liste zum Aufhängen. Bis 50 Mitglieder eine Seite, darüber
Vorder- und Rückseite.</li>
<?php endif; ?>
<li><b>Journal-Vorschau</b>: alle Buchungen mit Herkunft.</li>
<?php if ($kann('csv_import')): ?>
<li><b>CSV Upload</b>: Einzahlungen aus einer Datei einlesen erst Vorschau, dann
buchen. Zeilen ohne eindeutige Zuordnung werden nicht verbucht.</li>
<?php endif; ?>
</ul>
<h3>Info-Mails versenden</h3>
<p>Unter <b>Mailversand</b> lassen sich Mitglieder über ihren Stand informieren. Der
<b>Dry-Run</b> zeigt zuerst, wer eine Mail bekäme, ohne etwas zu verschicken. Das
Versandlog hält fest, was tatsächlich rausging.</p>
<h3>Jahresabschluss</h3>
<p>Verteilt einen frei wählbaren Gesamtbetrag als Guthaben auf alle Mitglieder
anteilig zu ihren Strichen im laufenden Jahr. Auch hier gilt: erst <b>Dry-Run</b>
zur Vorschau, dann buchen. Beim echten Lauf werden die Mitglieder per Mail informiert.</p>
<?php if ($kann('mail_dispatch') || $kann('year_closing')): ?>
<h3>Mails und Jahresabschluss</h3>
<ul>
<?php if ($kann('mail_dispatch')): ?>
<li><b>Info-Mail versenden</b>: informiert Mitglieder über ihren Stand. Der Dry-Run
zeigt vorher, wer eine Mail bekäme.</li>
<?php endif; ?>
<?php if ($kann('year_closing')): ?>
<li><b>Jahresabschluss</b>: verteilt einen frei wählbaren Betrag anteilig zu den
Strichen des Jahres als Guthaben. Auch hier erst Dry-Run, dann buchen.</li>
<?php endif; ?>
</ul>
<?php endif; ?>
<?php endif; ?>
<?php if ($istAdmin): ?>
<hr>
<h2>Für Administratoren</h2>
<p><small>Sichtbar für die Rollen <b>Administrator</b> und <b>Inhaber</b>.</small></p>
<h3>Mitglieder verwalten</h3>
<ul>
<li><b>Anlegen und bearbeiten</b> von Mitgliedern (Name, E-Mail, PayPal-Name).</li>
<li><b>PayPal-Name</b>: entscheidend für die automatische Zuordnung von Zahlungen.</li>
<li><b>Deaktivieren</b> statt löschen: Das Mitglied verschwindet aus den Listen,
die Buchungshistorie bleibt erhalten.</li>
<li><b>Anonymisieren</b>: ersetzt Name und E-Mail durch einen Platzhalter (DSGVO-Auskunft),
die Buchungen der Kasse bleiben für die Abrechnung bestehen.</li>
<li><b>Zugang gewähren / entziehen</b>: steuert, ob ein Mitglied sich anmelden kann.</li>
<li><b>CSV-Import</b> für viele Mitglieder auf einmal eine passende Vorlage gibt es
zum Herunterladen.</li>
<li><b>Deaktivieren</b> statt löschen: das Mitglied verschwindet aus den Listen, die
Buchungshistorie bleibt.</li>
<li><b>Anonymisieren</b>: ersetzt Name und E-Mail durch einen Platzhalter, die Buchungen
der Kasse bleiben bestehen.</li>
<li><b>Zugang gewähren / entziehen</b> steuert, ob sich jemand anmelden kann.</li>
</ul>
<h3>Hinweise verwalten</h3>
<p>Ein Hinweis erscheint als gelber Balken oben auf jeder Seite z.&nbsp;B. „Kaffeekasse
ist leer“. Jeder Hinweis hat ein <b>Gültig bis</b>-Datum und verschwindet danach
automatisch.</p>
<h3>Hinweise</h3>
<p>Ein Hinweis erscheint als gelber Balken oben auf jeder Seite und verschwindet nach dem
<b>Gültig bis</b>-Datum automatisch.</p>
<h3>Mandant-Einstellungen</h3>
<p>Hier stellst du das Verhalten der Kaffeeliste ein:</p>
<ul>
<li><b>Preis pro Strich</b> Grundlage jeder Verbrauchsbuchung.</li>
<li><b>Listenfenster in Tagen</b> Zeitraum für die Vorder-/Rückseiten-Aufteilung.</li>
<li><b>Schulden-Warnschwelle</b> ab welchem Minus gewarnt bzw. erinnert wird.</li>
<li><b>Bezahloptionen</b> Barzahlung, PayPal und Überweisung samt Kontaktdaten.
Nur aktivierte Wege erscheinen bei den Mitgliedern.</li>
<li><b>Web-Striche erlauben</b> ob Mitglieder selbst eintragen dürfen.</li>
<li><b>Ausdruck</b> Sortierung, Zeilenhöhe, leere Zeilen, Wasserzeichen und Fußzeile.</li>
<li><b>Zahlungserinnerungen</b> automatische Mails an Mitglieder unterhalb der
Warnschwelle, samt Mindestabstand zwischen zwei Erinnerungen.</li>
</ul>
<p>Im <b>Protokoll</b> unten auf der Seite steht, wer wann welche Änderung vorgenommen hat.</p>
<p>Preis pro Strich, Listenfenster, Warnschwelle, Bezahloptionen, Web-Striche, Gestaltung
des Ausdrucks<?php echo $kann('branding') ? ', eigenes Design (Logo und Akzentfarbe)' : ''; ?>
und Zahlungserinnerungen. Unten steht das Protokoll aller Admin-Änderungen.</p>
<h3>Konto, Abo und Daten</h3>
<ul>
<li><b>Kundenkonto</b>: Tarif, Rechnungen und Zahlungsdaten.</li>
<li><b>Datenexport</b>: alle Daten des Mandanten als Datei für ein Backup oder
einen Umzug.</li>
<li><b>Mandant löschen</b>: entfernt den Mandanten mit allen Daten endgültig.</li>
<?php if ($kann('data_export')): ?>
<li><b>Datenexport</b>: alle Daten des Mandanten als Datei.</li>
<?php endif; ?>
<li><b>Mandant löschen</b>: entfernt alles endgültig<?php echo $kann('data_export') ? ' vorher Datenexport ziehen' : ''; ?>.</li>
</ul>
<div class="hint-box error">
<p><b>Das Löschen eines Mandanten kann nicht rückgängig gemacht werden.</b> Lade dir
vorher über den Datenexport eine Kopie herunter.</p>
</div>
<h3>Rollen im Überblick</h3>
<table>
@@ -231,11 +180,10 @@ include "nav.php";
</table>
<?php endif; ?>
<?php if ($kann('faq')): ?>
<hr>
<h3>Noch Fragen?</h3>
<p>Häufige Fragen und die Antworten eurer Verwaltung stehen unter
<a href="faq.php">FAQ Kaffeeliste</a>.</p>
<p>Weitere Fragen beantwortet eure Verwaltung unter <a href="faq.php">FAQ Kaffeeliste</a>.</p>
<?php endif; ?>
</div>
</section>