diff --git a/app/paypal-inbox.php b/app/paypal-inbox.php index 3168c48..0c74335 100644 --- a/app/paypal-inbox.php +++ b/app/paypal-inbox.php @@ -328,3 +328,54 @@ function paypal_ignore_payment(PDO $pdo, int $tenantId, int $paymentId, ?int $ac return ['ok' => false, 'error' => 'Diese Zahlung ist nicht (mehr) offen.']; } + +/** + * Anzahl der offenen Zahlungen in der Warteschlange. Bewusst als eigene + * Zaehl-Abfrage neben paypal_fetch_unmatched(): die Navigation braucht nur + * die Information "gibt es noch etwas zu tun", nicht die Datensaetze. + */ +function paypal_count_unmatched(PDO $pdo, int $tenantId): int +{ + static $cache = []; + + if (array_key_exists($tenantId, $cache)) { + return $cache[$tenantId]; + } + + try { + $stmt = $pdo->prepare( + "SELECT COUNT(*) FROM paypal_payments WHERE tenant_id = ? AND status = 'unmatched'" + ); + $stmt->execute([$tenantId]); + $cache[$tenantId] = (int)$stmt->fetchColumn(); + } catch (Throwable $e) { + // Fehlt die Tabelle, gibt es auch keine Warteschlange - die + // Navigation darf daran nicht scheitern. + $cache[$tenantId] = 0; + } + + return $cache[$tenantId]; +} + +/** + * Darf die Zuordnungsseite geoeffnet werden? Die Funktion kennt drei Faelle: + * der Betreiber hat gesperrt (nein), der Mandant bietet PayPal an (ja) - und + * dazwischen der Fall, dass der Mandant PayPal gerade abgeschaltet hat, + * aber noch Zahlungen unzugeordnet in der Warteschlange liegen. Die waeren + * sonst weder ueber das Menue noch ueber die URL erreichbar; die Seite bleibt + * deshalb offen, bis die Warteschlange leer ist. + */ +function paypal_inbox_accessible(PDO $pdo, int $tenantId): bool +{ + require_once __DIR__ . '/features.php'; + + if (!app_feature_enabled($pdo, $tenantId, 'paypal_inbox')) { + return false; + } + + if (app_feature_available($pdo, $tenantId, 'paypal_inbox')) { + return true; + } + + return paypal_count_unmatched($pdo, $tenantId) > 0; +} diff --git a/docs/backoffice.md b/docs/backoffice.md index 050f01e..376b438 100644 --- a/docs/backoffice.md +++ b/docs/backoffice.md @@ -105,6 +105,13 @@ Design-Entscheidungen: Aufruf erscheint statt des Betreiber-Hinweises `app_feature_tenant_notice_html()` mit dem Weg zurück in die Mandant-Einstellungen. +- **Ausnahme: offene Warteschlange.** Schaltet ein Mandant PayPal ab, + während noch nicht zugeordnete Zahlungen liegen, wären diese weder über + Menü noch über URL erreichbar. `paypal_inbox_accessible()` + (`app/paypal-inbox.php`) hält Menüpunkt und Seite deshalb offen, solange + `paypal_count_unmatched()` etwas findet – mit einem Hinweis auf der + Seite. Ist die Warteschlange abgearbeitet, schließt sie sich von selbst. + Eine Sperre durch den Betreiber sticht auch diese Ausnahme. - Jede Änderung landet als `backoffice.features_updated` im Audit-Log des betroffenen Mandanten – wie jeder andere Back-Office-Zugriff auch. diff --git a/footer.php b/footer.php index 72f6f89..879348b 100644 --- a/footer.php +++ b/footer.php @@ -45,6 +45,15 @@ $saasNavFeature = static function (string $key) use ($saasNavTenantId): bool { return app_feature_available(app_db_pdo(), $saasNavTenantId, $key); }; +// Sonderfall PayPal: abgeschaltet heisst normalerweise unsichtbar - solange +// aber noch Zahlungen unzugeordnet in der Warteschlange liegen, bleibt der +// Menuepunkt stehen, sonst kaeme niemand mehr an sie heran. +$saasNavPaypalInbox = true; +if ($saasNavTenantId > 0) { + require_once __DIR__ . '/app/paypal-inbox.php'; + $saasNavPaypalInbox = paypal_inbox_accessible(app_db_pdo(), $saasNavTenantId); +} + // Das Back-Office war bisher nur ueber die direkte URL erreichbar. Es ist die // Zentralstelle des Betreibers und gehoert deshalb ins Menue - aber nur fuer // Platform-Admins, nicht fuer Mandanten-Rollen. @@ -74,7 +83,7 @@ if ($saasNavUser !== null) { Verwaltung