From bc370ef4754fe2f3cec471875d613c3e640f58b1 Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Tue, 31 Mar 2026 02:14:33 +0200
Subject: [PATCH] =?UTF-8?q?Alle=207=20Stellen=20im=20Code,=20die=20Stripe-?=
=?UTF-8?q?Objekte=20in=20Dicts=20konvertieren,=20nutzen=20jetzt=20stripeT?=
=?UTF-8?q?oDict().=20Das=20funktioniert=20unabh=C3=A4ngig=20von=20der=20S?=
=?UTF-8?q?tripe-Bibliotheksversion=20auf=20DEV=20und=20INT.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
modules/routes/routeBilling.py | 12 ++++++++----
modules/routes/routeSubscription.py | 4 ++--
.../mainServiceSubscription.py | 12 ++++++++----
.../serviceSubscription/stripeBootstrap.py | 3 ++-
modules/shared/stripeClient.py | 17 ++++++++++++++++-
5 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/modules/routes/routeBilling.py b/modules/routes/routeBilling.py
index d899ad2a..5029e485 100644
--- a/modules/routes/routeBilling.py
+++ b/modules/routes/routeBilling.py
@@ -875,7 +875,8 @@ def confirmCheckoutSession(
if not session:
raise HTTPException(status_code=404, detail="Stripe Checkout Session not found")
- session_dict = session.to_dict_recursive() if hasattr(session, "to_dict_recursive") else dict(session)
+ from modules.shared.stripeClient import stripeToDict
+ session_dict = stripeToDict(session)
metadata = session_dict.get("metadata") or {}
mandate_id = metadata.get("mandateId")
user_id = metadata.get("userId") or None
@@ -995,7 +996,8 @@ def _handleSubscriptionCheckoutCompleted(session, eventId: str) -> None:
from datetime import datetime, timezone
if not isinstance(session, dict):
- session = dict(session)
+ from modules.shared.stripeClient import stripeToDict
+ session = stripeToDict(session)
metadata = session.get("metadata") or {}
subscriptionRecordId = metadata.get("subscriptionRecordId")
@@ -1010,7 +1012,8 @@ def _handleSubscriptionCheckoutCompleted(session, eventId: str) -> None:
try:
from modules.shared.stripeClient import getStripeClient
stripe = getStripeClient()
- subObj = dict(stripe.Subscription.retrieve(stripeSub))
+ from modules.shared.stripeClient import stripeToDict
+ subObj = stripeToDict(stripe.Subscription.retrieve(stripeSub))
metadata = subObj.get("metadata") or {}
subscriptionRecordId = metadata.get("subscriptionRecordId")
mandateId = metadata.get("mandateId")
@@ -1042,7 +1045,8 @@ def _handleSubscriptionCheckoutCompleted(session, eventId: str) -> None:
try:
from modules.shared.stripeClient import getStripeClient
stripe = getStripeClient()
- stripeSub = dict(stripe.Subscription.retrieve(stripeSubId, expand=["items"]))
+ from modules.shared.stripeClient import stripeToDict
+ stripeSub = stripeToDict(stripe.Subscription.retrieve(stripeSubId, expand=["items"]))
if stripeSub.get("current_period_start"):
stripeData["currentPeriodStart"] = datetime.fromtimestamp(
diff --git a/modules/routes/routeSubscription.py b/modules/routes/routeSubscription.py
index 99bdb4e6..97a7f23b 100644
--- a/modules/routes/routeSubscription.py
+++ b/modules/routes/routeSubscription.py
@@ -282,10 +282,10 @@ def verifyCheckout(
_assertMandateAdmin(context, mandateId)
try:
- from modules.shared.stripeClient import getStripeClient
+ from modules.shared.stripeClient import getStripeClient, stripeToDict
stripe = getStripeClient()
rawSession = stripe.checkout.Session.retrieve(data.sessionId)
- session = dict(rawSession)
+ session = stripeToDict(rawSession)
except Exception as e:
logger.error("Failed to retrieve checkout session %s: %s", data.sessionId, e)
raise HTTPException(status_code=400, detail="Invalid session ID")
diff --git a/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py b/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py
index 5d2249a0..9535a2da 100644
--- a/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py
+++ b/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py
@@ -425,7 +425,8 @@ class SubscriptionService:
try:
from modules.shared.stripeClient import getStripeClient
stripe = getStripeClient()
- stripeSub = dict(stripe.Subscription.modify(stripeSubId, cancel_at_period_end=True))
+ from modules.shared.stripeClient import stripeToDict
+ stripeSub = stripeToDict(stripe.Subscription.modify(stripeSubId, cancel_at_period_end=True))
pUrl = (stripeSub.get("metadata") or {}).get("platformUrl", "")
except Exception as e:
logger.error("Failed to set cancel_at_period_end for %s: %s", stripeSubId, e)
@@ -488,7 +489,8 @@ class SubscriptionService:
try:
from modules.shared.stripeClient import getStripeClient
stripe = getStripeClient()
- stripeSub = dict(stripe.Subscription.retrieve(stripeSubId))
+ from modules.shared.stripeClient import stripeToDict
+ stripeSub = stripeToDict(stripe.Subscription.retrieve(stripeSubId))
pUrl = (stripeSub.get("metadata") or {}).get("platformUrl", "")
stripe.Subscription.cancel(stripeSubId)
except Exception as e:
@@ -673,7 +675,8 @@ def _buildInvoiceSummaryHtml(
stripe = getStripeClient()
invoices = stripe.Invoice.list(subscription=stripeSubId, limit=1)
if invoices.data:
- inv = dict(invoices.data[0]) if not isinstance(invoices.data[0], dict) else invoices.data[0]
+ from modules.shared.stripeClient import stripeToDict
+ inv = stripeToDict(invoices.data[0])
hostedUrl = inv.get("hosted_invoice_url", "")
if hostedUrl:
invoiceLink = (
@@ -715,7 +718,8 @@ def _buildCancelSummaryHtml(subRecord: Dict[str, Any], platformUrl: str = "") ->
stripe = getStripeClient()
invoices = stripe.Invoice.list(subscription=stripeSubId, limit=1)
if invoices.data:
- inv = dict(invoices.data[0]) if not isinstance(invoices.data[0], dict) else invoices.data[0]
+ from modules.shared.stripeClient import stripeToDict
+ inv = stripeToDict(invoices.data[0])
hostedUrl = inv.get("hosted_invoice_url", "")
if hostedUrl:
parts.append(
diff --git a/modules/serviceCenter/services/serviceSubscription/stripeBootstrap.py b/modules/serviceCenter/services/serviceSubscription/stripeBootstrap.py
index 1e44217b..14e9424a 100644
--- a/modules/serviceCenter/services/serviceSubscription/stripeBootstrap.py
+++ b/modules/serviceCenter/services/serviceSubscription/stripeBootstrap.py
@@ -108,7 +108,8 @@ def _findExistingStripePrice(stripe, productId: str, unitAmount: int, interval:
def _getStripePriceAmount(stripe, priceId: str) -> Optional[int]:
"""Retrieve the unit_amount (in Rappen) of an existing Stripe Price."""
try:
- price = dict(stripe.Price.retrieve(priceId))
+ from modules.shared.stripeClient import stripeToDict
+ price = stripeToDict(stripe.Price.retrieve(priceId))
return price.get("unit_amount") if price else None
except Exception:
return None
diff --git a/modules/shared/stripeClient.py b/modules/shared/stripeClient.py
index 9c7b4c67..3f7dd3a7 100644
--- a/modules/shared/stripeClient.py
+++ b/modules/shared/stripeClient.py
@@ -8,13 +8,28 @@ API key, API version, and fallback handling across billing and subscription flow
"""
import logging
-from typing import Optional
+import json
+from typing import Any, Dict, Optional
logger = logging.getLogger(__name__)
_stripeInitialized = False
+def stripeToDict(obj) -> Dict[str, Any]:
+ """Convert a Stripe object to a plain dict, compatible with all stripe-python versions."""
+ if isinstance(obj, dict):
+ return obj
+ if hasattr(obj, "to_dict_recursive"):
+ return obj.to_dict_recursive()
+ if hasattr(obj, "to_dict"):
+ return obj.to_dict()
+ try:
+ return json.loads(str(obj))
+ except (json.JSONDecodeError, TypeError):
+ return dict(obj)
+
+
def getStripeClient():
"""
Initialize and return the configured Stripe SDK module.