From b142c0fa6cf5027039b487f4e40c515cbcc4f905 Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Tue, 31 Mar 2026 02:05:16 +0200
Subject: [PATCH] NT-Problem: Unhandled exception: get
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Root Cause: Die Stripe-Python-Bibliothek auf INT hat keine .get() Methode auf Stripe-Objekten. Wenn session.get("payment_status") aufgerufen wird, sucht Python via __getattr__ nach einem Feld namens "get" → AttributeError("get").
Bestätigung: In routeBilling.py gab es bereits einen hasattr(session, "get")-Check (Zeile 998) — jemand kannte das Problem.
Fix: Alle Stripe-Objekte werden sofort nach dem API-Call in dict() konvertiert
---
modules/routes/routeBilling.py | 18 +++++++++++-------
modules/routes/routeSubscription.py | 3 ++-
.../mainServiceSubscription.py | 10 ++++++----
.../serviceSubscription/stripeBootstrap.py | 2 +-
4 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/modules/routes/routeBilling.py b/modules/routes/routeBilling.py
index 0f612d45..d899ad2a 100644
--- a/modules/routes/routeBilling.py
+++ b/modules/routes/routeBilling.py
@@ -994,9 +994,10 @@ def _handleSubscriptionCheckoutCompleted(session, eventId: str) -> None:
from modules.security.rootAccess import getRootUser
from datetime import datetime, timezone
- metadata = {}
- if hasattr(session, "get"):
- metadata = session.get("metadata") or {}
+ if not isinstance(session, dict):
+ session = dict(session)
+
+ metadata = session.get("metadata") or {}
subscriptionRecordId = metadata.get("subscriptionRecordId")
mandateId = metadata.get("mandateId")
planKey = metadata.get("planKey", "")
@@ -1009,7 +1010,7 @@ def _handleSubscriptionCheckoutCompleted(session, eventId: str) -> None:
try:
from modules.shared.stripeClient import getStripeClient
stripe = getStripeClient()
- subObj = stripe.Subscription.retrieve(stripeSub)
+ subObj = dict(stripe.Subscription.retrieve(stripeSub))
metadata = subObj.get("metadata") or {}
subscriptionRecordId = metadata.get("subscriptionRecordId")
mandateId = metadata.get("mandateId")
@@ -1041,7 +1042,7 @@ def _handleSubscriptionCheckoutCompleted(session, eventId: str) -> None:
try:
from modules.shared.stripeClient import getStripeClient
stripe = getStripeClient()
- stripeSub = stripe.Subscription.retrieve(stripeSubId, expand=["items"])
+ stripeSub = dict(stripe.Subscription.retrieve(stripeSubId, expand=["items"]))
if stripeSub.get("current_period_start"):
stripeData["currentPeriodStart"] = datetime.fromtimestamp(
@@ -1054,8 +1055,11 @@ def _handleSubscriptionCheckoutCompleted(session, eventId: str) -> None:
from modules.serviceCenter.services.serviceSubscription.stripeBootstrap import getStripePricesForPlan
priceMapping = getStripePricesForPlan(planKey)
- for item in stripeSub.get("items", {}).get("data", []):
- priceId = item.get("price", {}).get("id", "")
+ items = stripeSub.get("items") or {}
+ if not isinstance(items, dict):
+ items = dict(items)
+ for item in items.get("data", []):
+ priceId = (item.get("price") or {}).get("id", "")
if priceMapping and priceId == priceMapping.stripePriceIdUsers:
stripeData["stripeItemIdUsers"] = item["id"]
elif priceMapping and priceId == priceMapping.stripePriceIdInstances:
diff --git a/modules/routes/routeSubscription.py b/modules/routes/routeSubscription.py
index 9f1f0bf8..99bdb4e6 100644
--- a/modules/routes/routeSubscription.py
+++ b/modules/routes/routeSubscription.py
@@ -284,7 +284,8 @@ def verifyCheckout(
try:
from modules.shared.stripeClient import getStripeClient
stripe = getStripeClient()
- session = stripe.checkout.Session.retrieve(data.sessionId)
+ rawSession = stripe.checkout.Session.retrieve(data.sessionId)
+ session = dict(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 55bff123..5d2249a0 100644
--- a/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py
+++ b/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py
@@ -425,7 +425,7 @@ class SubscriptionService:
try:
from modules.shared.stripeClient import getStripeClient
stripe = getStripeClient()
- stripeSub = stripe.Subscription.modify(stripeSubId, cancel_at_period_end=True)
+ stripeSub = dict(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 +488,7 @@ class SubscriptionService:
try:
from modules.shared.stripeClient import getStripeClient
stripe = getStripeClient()
- stripeSub = stripe.Subscription.retrieve(stripeSubId)
+ stripeSub = dict(stripe.Subscription.retrieve(stripeSubId))
pUrl = (stripeSub.get("metadata") or {}).get("platformUrl", "")
stripe.Subscription.cancel(stripeSubId)
except Exception as e:
@@ -673,7 +673,8 @@ def _buildInvoiceSummaryHtml(
stripe = getStripeClient()
invoices = stripe.Invoice.list(subscription=stripeSubId, limit=1)
if invoices.data:
- hostedUrl = invoices.data[0].get("hosted_invoice_url", "")
+ inv = dict(invoices.data[0]) if not isinstance(invoices.data[0], dict) else invoices.data[0]
+ hostedUrl = inv.get("hosted_invoice_url", "")
if hostedUrl:
invoiceLink = (
f''
@@ -714,7 +715,8 @@ def _buildCancelSummaryHtml(subRecord: Dict[str, Any], platformUrl: str = "") ->
stripe = getStripeClient()
invoices = stripe.Invoice.list(subscription=stripeSubId, limit=1)
if invoices.data:
- hostedUrl = invoices.data[0].get("hosted_invoice_url", "")
+ inv = dict(invoices.data[0]) if not isinstance(invoices.data[0], dict) else invoices.data[0]
+ hostedUrl = inv.get("hosted_invoice_url", "")
if hostedUrl:
parts.append(
f'
'
diff --git a/modules/serviceCenter/services/serviceSubscription/stripeBootstrap.py b/modules/serviceCenter/services/serviceSubscription/stripeBootstrap.py
index edb2df1f..1e44217b 100644
--- a/modules/serviceCenter/services/serviceSubscription/stripeBootstrap.py
+++ b/modules/serviceCenter/services/serviceSubscription/stripeBootstrap.py
@@ -108,7 +108,7 @@ 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 = stripe.Price.retrieve(priceId)
+ price = dict(stripe.Price.retrieve(priceId))
return price.get("unit_amount") if price else None
except Exception:
return None