Files
chat_backend/llm_be/finance/services/stripe_service.py
T
westfarn ac59af8b3e
CI / test (pull_request) Successful in 10s
Unit Tests / test (pull_request) Successful in 9s
Add Stripe Customer Portal session API for account billing.
Expose POST /api/finance/portal/ so authenticated users can open Stripe's hosted portal for plan changes, payment methods, and cancellations (chat_web_app#33 companion).
2026-07-31 05:48:09 -05:00

98 lines
2.8 KiB
Python

"""Stripe Checkout and Billing Portal session helpers."""
from __future__ import annotations
from typing import Any
import stripe
from django.conf import settings
from finance.models import Invoice
class StripeNotConfiguredError(RuntimeError):
"""Raised when Stripe secret key is missing."""
def configure_stripe() -> str:
secret = settings.STRIPE_SECRET_KEY
if not secret:
raise StripeNotConfiguredError(
"STRIPE_SECRET_KEY is not configured. Set it in the environment."
)
stripe.api_key = secret
return secret
def subscription_line_items() -> list[dict[str, Any]]:
"""Build Checkout line_items from settings-backed subscription pricing."""
price_id = settings.STRIPE_PRICE_ID
if price_id:
return [{"price": price_id, "quantity": 1}]
return [
{
"price_data": {
"currency": settings.SUBSCRIPTION_PRICE_CURRENCY,
"unit_amount": settings.SUBSCRIPTION_PRICE_AMOUNT_CENTS,
"recurring": {"interval": settings.SUBSCRIPTION_PRICE_INTERVAL},
"product_data": {
"name": settings.SUBSCRIPTION_PRODUCT_NAME,
},
},
"quantity": 1,
}
]
def create_checkout_session(
*,
user,
success_url: str | None = None,
cancel_url: str | None = None,
):
"""Create a Stripe Checkout Session for the subscription plan."""
configure_stripe()
metadata = {
"user_id": str(user.pk),
"company_id": str(user.company_id) if user.company_id else "",
}
customer_email = getattr(user, "email", None) or None
session = stripe.checkout.Session.create(
mode="subscription",
line_items=subscription_line_items(),
success_url=success_url or settings.STRIPE_CHECKOUT_SUCCESS_URL,
cancel_url=cancel_url or settings.STRIPE_CHECKOUT_CANCEL_URL,
customer_email=customer_email,
client_reference_id=str(user.pk),
metadata=metadata,
subscription_data={"metadata": metadata},
)
return session
def resolve_stripe_customer_id(*, user) -> str | None:
"""Return the most recent Stripe customer id stored on the user's invoices."""
return (
Invoice.objects.filter(user=user)
.exclude(stripe_customer_id="")
.order_by("-created")
.values_list("stripe_customer_id", flat=True)
.first()
)
def create_billing_portal_session(
*,
customer_id: str,
return_url: str | None = None,
):
"""Create a Stripe Customer Portal session for plan/payment/cancel management."""
configure_stripe()
return stripe.billing_portal.Session.create(
customer=customer_id,
return_url=return_url or settings.STRIPE_PORTAL_RETURN_URL,
)