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).
This commit is contained in:
@@ -11,10 +11,13 @@ from finance.serializers import (
|
||||
CheckoutSessionSerializer,
|
||||
InvoiceSerializer,
|
||||
PaymentSerializer,
|
||||
PortalSessionSerializer,
|
||||
)
|
||||
from finance.services.stripe_service import (
|
||||
StripeNotConfiguredError,
|
||||
create_billing_portal_session,
|
||||
create_checkout_session,
|
||||
resolve_stripe_customer_id,
|
||||
)
|
||||
from finance.services.webhooks import dispatch_stripe_event
|
||||
|
||||
@@ -72,6 +75,48 @@ class CreateCheckoutSessionView(APIView):
|
||||
)
|
||||
|
||||
|
||||
class CreateBillingPortalSessionView(APIView):
|
||||
"""Create a Stripe Customer Portal session and return the hosted URL."""
|
||||
|
||||
def post(self, request):
|
||||
serializer = PortalSessionSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
customer_id = resolve_stripe_customer_id(user=request.user)
|
||||
if not customer_id:
|
||||
return Response(
|
||||
{
|
||||
"detail": (
|
||||
"No Stripe customer found for this account. "
|
||||
"Complete Checkout first to manage billing."
|
||||
)
|
||||
},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
try:
|
||||
session = create_billing_portal_session(
|
||||
customer_id=customer_id,
|
||||
return_url=serializer.validated_data.get("return_url"),
|
||||
)
|
||||
except StripeNotConfiguredError as exc:
|
||||
return Response(
|
||||
{"detail": str(exc)},
|
||||
status=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
)
|
||||
except stripe.StripeError as exc:
|
||||
logger.exception("Stripe Billing Portal Session creation failed")
|
||||
return Response(
|
||||
{"detail": str(getattr(exc, "user_message", None) or exc)},
|
||||
status=status.HTTP_502_BAD_GATEWAY,
|
||||
)
|
||||
|
||||
return Response(
|
||||
{"portal_url": session.url},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
|
||||
class InvoiceListView(APIView):
|
||||
def get(self, request):
|
||||
invoices = Invoice.objects.filter(user=request.user)
|
||||
|
||||
Reference in New Issue
Block a user