Harte Teilnehmer-Obergrenze je Tarif statt automatischem Stufenwechsel

Statt automatisch hochzustufen, blockiert das Anlegen/Reaktivieren
weiterer aktiver Mitglieder, sobald das Limit des gebuchten Tarifs
erreicht ist (Neuanlage, Bearbeiten mit Statuswechsel, Aktivieren-
Button). mitarbeiterverwalten.php zeigt die aktuelle Auslastung an.
Neuer Regressionstest scripts/check-billing-capacity.php deckt alle
drei Enforcement-Stellen ab.
This commit is contained in:
2026-07-17 11:19:00 +02:00
parent 73d599f85b
commit d2330c81cd
4 changed files with 334 additions and 4 deletions
+24 -1
View File
@@ -5,6 +5,7 @@ include "functions.php";
require_once __DIR__ . "/app/ledger.php";
require_once __DIR__ . "/app/saas-mail.php";
require_once __DIR__ . "/app/audit.php";
require_once __DIR__ . "/app/billing.php";
app_require_csrf();
include "header.php";
include "headerline.php";
@@ -59,6 +60,8 @@ if($hasAccess){
if ($name === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$fehler = 'Bitte einen Namen und eine gültige E-Mail-Adresse angeben.';
} elseif ($aktiv && !billing_has_capacity_for($pdo, $tenantId)) {
$fehler = billing_capacity_error_message($pdo, $tenantId);
} else {
try {
$neueId = ledger_create_participant($pdo, $tenantId, $name, $email, $paypalname, $aktiv);
@@ -75,8 +78,18 @@ if($hasAccess){
$paypalname = trim((string)($_POST["paypalname"] ?? ''));
$aktiv = isset($_POST["aktiv"]);
$warAktiv = false;
foreach (ledger_fetch_participants_for_admin($pdo, $tenantId) as $m) {
if ($m['participant_id'] === $participantId) {
$warAktiv = (bool)$m['active'];
break;
}
}
if ($name === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$fehler = 'Bitte einen Namen und eine gültige E-Mail-Adresse angeben.';
} elseif ($aktiv && !$warAktiv && !billing_has_capacity_for($pdo, $tenantId)) {
$fehler = billing_capacity_error_message($pdo, $tenantId);
} elseif (ledger_update_participant($pdo, $tenantId, $participantId, $name, $email, $paypalname, $aktiv)) {
app_audit_log($pdo, $tenantId, $actorUserId, 'participant.updated', 'participant', $participantId, ['name' => $name, 'email' => $email]);
$meldung = 'Mitglied wurde gespeichert.';
@@ -85,7 +98,9 @@ if($hasAccess){
}
} elseif ($aktion === 'aktivieren' || $aktion === 'deaktivieren') {
$participantId = (int)$_POST["mitgliedID"];
if (ledger_set_participant_active($pdo, $tenantId, $participantId, $aktion === 'aktivieren')) {
if ($aktion === 'aktivieren' && !billing_has_capacity_for($pdo, $tenantId)) {
$fehler = billing_capacity_error_message($pdo, $tenantId);
} elseif (ledger_set_participant_active($pdo, $tenantId, $participantId, $aktion === 'aktivieren')) {
app_audit_log($pdo, $tenantId, $actorUserId, $aktion === 'aktivieren' ? 'participant.activated' : 'participant.deactivated', 'participant', $participantId);
$meldung = $aktion === 'aktivieren' ? 'Mitglied wurde aktiviert.' : 'Mitglied wurde deaktiviert.';
} else {
@@ -144,6 +159,9 @@ if($hasAccess){
}
$mitglieder = ledger_fetch_participants_for_admin($pdo, $tenantId);
$billingInfo = billing_fetch_or_init($pdo, $tenantId);
$billingPlan = billing_plans()[$billingInfo['plan_code']] ?? null;
$aktiveMitgliederAnzahl = billing_count_active_participants($pdo, $tenantId);
$rollenLabels = ['owner' => 'Inhaber', 'admin' => 'Administrator', 'treasurer' => 'Kassenwart', 'member' => 'Mitglied', 'viewer' => 'Betrachter'];
$bearbeitenMitglied = null;
if ($bearbeitenId !== null) {
@@ -177,6 +195,11 @@ if($hasAccess){
<div class="hint-box"><p>Dev-Link zur Einladung: <a href="<?php echo saas_html($einladungslink); ?>"><?php echo saas_html($einladungslink); ?></a></p></div>
<?php endif; ?>
<p>Aktive Mitglieder: <?php echo (int)$aktiveMitgliederAnzahl; ?><?php echo $billingPlan['max_participants'] !== null ? ' von maximal ' . (int)$billingPlan['max_participants'] . ' im Tarif „' . saas_html($billingPlan['label']) . '"' : ' (Tarif „' . saas_html($billingPlan['label'] ?? $billingInfo['plan_code']) . '", unbegrenzt)'; ?>.
<?php if ($billingPlan['max_participants'] !== null && $aktiveMitgliederAnzahl >= $billingPlan['max_participants']): ?>
Limit erreicht für weitere aktive Mitglieder ist ein <a href="mandant-einstellungen.php">Upgrade</a> nötig.
<?php endif; ?></p>
<?php if ($bearbeitenMitglied !== null): ?>
<h3>Bearbeiten von <?php echo saas_html($bearbeitenMitglied['display_name']); ?></h3>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">