Stripe-Konfigurationsfehler in abo-upgrade.php sauber abfangen
billing_stripe_price_id() und der komplette abo-upgrade.php-Ablauf warfen bisher eine ungefangene RuntimeException (Fatal Error), sobald STRIPE_SECRET_KEY nicht gesetzt ist (z. B. lokale Dev-Umgebung ohne echte Stripe-Zugangsdaten) - bestand bereits im alten Code, ist durch die neue Tarif-Vergleichstabelle mit mehr Buchen-Buttons aber leichter auslösbar geworden. Jetzt: sauberer 502 'Bezahldienst nicht verfuegbar' statt Fatal-Error-Seite. Erstmals lokal per HTTP end-to-end gegen echten Dev-Server + MariaDB getestet (PHP 8.3 + MariaDB 11.4 als portable Binaries installiert, siehe docs/dev-mysql.md): eigener Test-Mandant mit 12 aktiven Teilnehmern, Tarif-Tabelle korrekt gerendert (5 Tarife, Pflicht-Upgrade-Hinweis, Buchen- Buttons, Enterprise-Anfrage-Link), Buchung von 'free' bei Ueberschreitung korrekt mit 400 abgelehnt, Buchung eines bezahlten Tarifs ohne Stripe-Key jetzt sauber mit 502 statt Fatal-Error-Crash. Alle bestehenden Regressionstests weiterhin gruen: Golden Master (104), Billing-Capacity (10), M8-Isolation (10), M8-Rollenmatrix (55).
This commit is contained in:
@@ -37,6 +37,7 @@ if (!billing_plan_selectable_for($pdo, $tenantId, $planCode)) {
|
|||||||
$billing = billing_fetch_or_init($pdo, $tenantId);
|
$billing = billing_fetch_or_init($pdo, $tenantId);
|
||||||
$baseUrl = saas_app_url('mandant-einstellungen.php');
|
$baseUrl = saas_app_url('mandant-einstellungen.php');
|
||||||
|
|
||||||
|
try {
|
||||||
// Fall 1: Wechsel auf "free" (kein Stripe-Preis) mit bestehender bezahlter
|
// Fall 1: Wechsel auf "free" (kein Stripe-Preis) mit bestehender bezahlter
|
||||||
// Subscription -> echtes Kuendigen der Subscription, kein Checkout noetig.
|
// Subscription -> echtes Kuendigen der Subscription, kein Checkout noetig.
|
||||||
if ($plans[$planCode]['stripe_lookup_key'] === null) {
|
if ($plans[$planCode]['stripe_lookup_key'] === null) {
|
||||||
@@ -129,3 +130,12 @@ app_audit_log($pdo, $tenantId, (int)$user['user_id'], 'billing.checkout_started'
|
|||||||
|
|
||||||
header('Location: ' . $result['url']);
|
header('Location: ' . $result['url']);
|
||||||
exit;
|
exit;
|
||||||
|
} catch (RuntimeException $e) {
|
||||||
|
// Stripe ist in dieser Umgebung nicht konfiguriert (fehlender
|
||||||
|
// STRIPE_SECRET_KEY, z. B. lokale Dev-Umgebung ohne echte Zugangsdaten)
|
||||||
|
// oder eine andere Konfigurationsvoraussetzung fehlt - sauber als
|
||||||
|
// Dienst-nicht-verfuegbar melden statt eine Fatal-Error-Seite zu zeigen.
|
||||||
|
app_audit_log($pdo, $tenantId, (int)$user['user_id'], 'billing.stripe_unavailable', 'tenant', $tenantId, ['plan_code' => $planCode, 'error' => $e->getMessage()]);
|
||||||
|
http_response_code(502);
|
||||||
|
exit('Der Bezahldienst ist aktuell nicht verfügbar. Bitte später erneut versuchen oder uns kontaktieren.');
|
||||||
|
}
|
||||||
|
|||||||
+9
-1
@@ -27,7 +27,10 @@ function billing_plans(): array
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the Stripe Price id for a plan by its lookup_key. Returns null
|
* Resolves the Stripe Price id for a plan by its lookup_key. Returns null
|
||||||
* for plans without a Stripe price (free, enterprise) or on API failure.
|
* for plans without a Stripe price (free, enterprise), on API failure, or
|
||||||
|
* when Stripe isn't configured at all (missing STRIPE_SECRET_KEY, e.g. in
|
||||||
|
* a local/dev environment) - callers already treat null as "not available
|
||||||
|
* right now", so this degrades gracefully instead of a fatal error.
|
||||||
*/
|
*/
|
||||||
function billing_stripe_price_id(string $planCode): ?string
|
function billing_stripe_price_id(string $planCode): ?string
|
||||||
{
|
{
|
||||||
@@ -37,7 +40,12 @@ function billing_stripe_price_id(string $planCode): ?string
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
$result = stripe_request('GET', 'prices', ['lookup_keys' => [$lookupKey], 'active' => 'true']);
|
$result = stripe_request('GET', 'prices', ['lookup_keys' => [$lookupKey], 'active' => 'true']);
|
||||||
|
} catch (RuntimeException $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if ($result['ok'] && !empty($result['data']['data'][0]['id'])) {
|
if ($result['ok'] && !empty($result['data']['data'][0]['id'])) {
|
||||||
return (string)$result['data']['data'][0]['id'];
|
return (string)$result['data']['data'][0]['id'];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user