fix: sync plan+tier after checkout, portal same-tab nav, cancel button always visible for paid plans, portal return URL to profile tab
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m44s

This commit is contained in:
2026-05-31 22:37:51 +02:00
parent 277589aea3
commit 00c54997bf
2 changed files with 31 additions and 11 deletions

View File

@@ -288,22 +288,40 @@ async def handle_checkout_completed(session: Dict):
subscription_ends_at = None
if isinstance(subscription_raw, str):
subscription_id = subscription_raw
# Not expanded — fetch subscription to get period end
try:
sub = stripe.Subscription.retrieve(subscription_raw)
subscription_id = sub["id"]
if sub.get("current_period_end"):
from datetime import timezone
subscription_ends_at = datetime.fromtimestamp(
sub["current_period_end"], tz=timezone.utc
)
except Exception:
subscription_id = subscription_raw
elif subscription_raw:
# Expanded subscription object (from sync path with expand=["subscription"])
# Expanded subscription object (from sync path)
subscription_id = subscription_raw.get("id")
period_end = subscription_raw.get("current_period_end")
if period_end:
subscription_ends_at = datetime.fromtimestamp(period_end).isoformat()
from datetime import timezone
subscription_ends_at = datetime.fromtimestamp(period_end, tz=timezone.utc)
# Derive tier from plan (DB constraint: only 'free' or 'pro')
tier = "pro" if plan in ("pro", "business", "enterprise") else "free"
update_user(user_id, {
"plan": plan,
"tier": tier,
"subscription_status": SubscriptionStatus.ACTIVE.value,
"stripe_subscription_id": subscription_id,
"stripe_customer_id": session.get("customer") or None,
"subscription_ends_at": subscription_ends_at,
"cancel_at_period_end": False,
"docs_translated_this_month": 0,
"pages_translated_this_month": 0,
})
logger.info("Checkout synced: user %s → plan=%s tier=%s sub=%s", user_id, plan, tier, subscription_id)
async def handle_subscription_updated(subscription: Dict):
@@ -420,16 +438,17 @@ async def get_billing_portal_url(user_id: str) -> Optional[str]:
"""Get Stripe billing portal URL for customer"""
if not is_stripe_configured():
return None
user = get_user_by_id(user_id)
if not user or not user.stripe_customer_id:
return None
try:
session = stripe.billing_portal.Session.create(
customer=user.stripe_customer_id,
return_url=f"{os.getenv('FRONTEND_URL', 'http://localhost:3000')}/dashboard"
return_url=f"{os.getenv('FRONTEND_URL', 'http://localhost:3000')}/dashboard/profile?tab=subscription"
)
return session.url
except:
except Exception as e:
logger.error("get_billing_portal_url error: %s", e)
return None