From 3be09679369a16453fb8d5024ce8e27bf42c92d2 Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Tue, 31 Mar 2026 00:15:47 +0200
Subject: [PATCH] fixed changed customer in stripe
---
.../mainServiceSubscription.py | 62 ++++++++++++++++---
1 file changed, 54 insertions(+), 8 deletions(-)
diff --git a/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py b/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py
index 944da4f7..55bff123 100644
--- a/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py
+++ b/modules/serviceCenter/services/serviceSubscription/mainServiceSubscription.py
@@ -283,14 +283,34 @@ class SubscriptionService:
subscriptionData["trial_end"] = trialEndTs
self._interface.updateFields(subRecord["id"], {"effectiveFrom": periodEnd.isoformat()})
- session = stripe.checkout.Session.create(
- mode="subscription",
- customer=stripeCustomerId,
- line_items=lineItems,
- success_url=successUrl,
- cancel_url=cancelUrl,
- subscription_data=subscriptionData,
- )
+ session = None
+ for attempt in range(2):
+ try:
+ session = stripe.checkout.Session.create(
+ mode="subscription",
+ customer=stripeCustomerId,
+ line_items=lineItems,
+ success_url=successUrl,
+ cancel_url=cancelUrl,
+ subscription_data=subscriptionData,
+ )
+ break
+ except Exception as e:
+ if attempt == 0 and self._isStripeMissingCustomerError(e):
+ logger.warning(
+ "Stripe reports missing customer %s for mandate %s — "
+ "clearing stored stripeCustomerId (wrong account, deleted customer, or copied DB).",
+ stripeCustomerId,
+ mandateId,
+ )
+ self._clearStoredStripeCustomerId(mandateId)
+ stripeCustomerId = self._resolveStripeCustomer(mandateId)
+ if not stripeCustomerId:
+ raise ValueError(
+ f"Could not recreate Stripe customer for mandate {mandateId}"
+ ) from e
+ continue
+ raise
if not session or not session.url:
raise ValueError("Stripe Checkout Session creation failed")
@@ -298,6 +318,32 @@ class SubscriptionService:
logger.info("Checkout session %s created for mandate %s, plan %s", session.id, mandateId, plan.planKey)
return session.url
+ @staticmethod
+ def _isStripeMissingCustomerError(exc: BaseException) -> bool:
+ code = getattr(exc, "code", None)
+ param = getattr(exc, "param", None)
+ if code == "resource_missing" and param == "customer":
+ return True
+ body = getattr(exc, "json_body", None)
+ if isinstance(body, dict):
+ err = body.get("error")
+ if isinstance(err, dict):
+ return err.get("code") == "resource_missing" and err.get("param") == "customer"
+ return False
+
+ def _clearStoredStripeCustomerId(self, mandateId: str) -> None:
+ try:
+ from modules.interfaces.interfaceDbBilling import getInterface as getBillingInterface
+
+ billingIf = getBillingInterface(self.currentUser, mandateId)
+ settings = billingIf.getSettings(mandateId)
+ if not settings or not settings.get("stripeCustomerId"):
+ return
+ billingIf.updateSettings(settings["id"], {"stripeCustomerId": None})
+ logger.info("Cleared stripeCustomerId on billing settings for mandate %s", mandateId)
+ except Exception as e:
+ logger.error("Failed to clear stripeCustomerId for mandate %s: %s", mandateId, e)
+
def _resolveStripeCustomer(self, mandateId: str) -> Optional[str]:
try:
from modules.interfaces.interfaceDbBilling import getInterface as getBillingInterface