infrasynth-backend-kit/infrasynth/billing/views.py
2026-08-28 14:38:47 -05:00

188 lines
6.4 KiB
Python

from rest_framework import mixins, status, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from .filters import (
BillingPlanFilter,
InvoiceFilter,
PaymentGatewayFilter,
PaymentTransactionFilter,
SubscriptionFilter,
)
from .models import (
BillingPlan,
Invoice,
PaymentGateway,
PaymentTransaction,
Subscription,
)
from .serializers import (
BillingPlanSerializer,
InvoiceSerializer,
PaymentGatewaySerializer,
PaymentTransactionSerializer,
SubscribeSerializer,
SubscriptionSerializer,
)
class PaymentGatewayViewSet(viewsets.ModelViewSet):
queryset = PaymentGateway.objects.all()
serializer_class = PaymentGatewaySerializer
permission_classes = [IsAuthenticated]
filterset_class = PaymentGatewayFilter
def initial(self, request, *args, **kwargs):
from infrasynth.features.services import FeatureService
if not FeatureService().is_enabled("billing", user=request.user):
from django.http import Http404
raise Http404()
super().initial(request, *args, **kwargs)
def get_queryset(self):
return PaymentGateway.objects.all()
class BillingPlanViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
queryset = BillingPlan.objects.filter(is_active=True)
serializer_class = BillingPlanSerializer
filterset_class = BillingPlanFilter
def get_permissions(self):
if self.action in ("list", "retrieve"):
return [AllowAny()]
return [IsAuthenticated()]
def initial(self, request, *args, **kwargs):
from infrasynth.features.services import FeatureService
if not FeatureService().is_enabled("billing", user=request.user):
from django.http import Http404
raise Http404()
super().initial(request, *args, **kwargs)
def get_queryset(self):
return BillingPlan.objects.filter(is_active=True).select_related("gateway")
class SubscriptionViewSet(viewsets.ModelViewSet):
queryset = Subscription.objects.all()
serializer_class = SubscriptionSerializer
permission_classes = [IsAuthenticated]
filterset_class = SubscriptionFilter
def initial(self, request, *args, **kwargs):
from infrasynth.features.services import FeatureService
if not FeatureService().is_enabled("billing", user=request.user):
from django.http import Http404
raise Http404()
super().initial(request, *args, **kwargs)
def get_queryset(self):
return Subscription.objects.select_related("plan", "gateway", "user").all()
@action(detail=False, methods=["post"])
def subscribe(self, request):
ser = SubscribeSerializer(data=request.data)
ser.is_valid(raise_exception=True)
from .services import BillingService
try:
result, gateway = BillingService().create_checkout_session(
ser.validated_data["plan_slug"],
request.user,
success_url=ser.validated_data.get("success_url"),
cancel_url=ser.validated_data.get("cancel_url"),
)
except ValueError as exc:
return Response({"detail": str(exc)}, status=status.HTTP_400_BAD_REQUEST)
return Response(
{
"checkout_url": result.checkout_url,
"session_id": result.session_id,
"client_secret": result.client_secret,
"gateway": gateway.slug,
"plan_slug": ser.validated_data["plan_slug"],
}
)
class InvoiceViewSet(viewsets.ModelViewSet):
queryset = Invoice.objects.all()
serializer_class = InvoiceSerializer
permission_classes = [IsAuthenticated]
filterset_class = InvoiceFilter
def initial(self, request, *args, **kwargs):
from infrasynth.features.services import FeatureService
if not FeatureService().is_enabled("billing", user=request.user):
from django.http import Http404
raise Http404()
super().initial(request, *args, **kwargs)
def get_queryset(self):
return Invoice.objects.select_related("subscription", "gateway", "user", "pdf_file").all()
class PaymentTransactionViewSet(viewsets.ReadOnlyModelViewSet):
queryset = PaymentTransaction.objects.all()
serializer_class = PaymentTransactionSerializer
permission_classes = [IsAuthenticated]
filterset_class = PaymentTransactionFilter
def initial(self, request, *args, **kwargs):
from infrasynth.features.services import FeatureService
if not FeatureService().is_enabled("billing", user=request.user):
from django.http import Http404
raise Http404()
super().initial(request, *args, **kwargs)
def get_queryset(self):
return PaymentTransaction.objects.select_related("invoice", "gateway").all()
class WebhookViewSet(viewsets.GenericViewSet):
permission_classes = [AllowAny]
@action(detail=False, methods=["post"])
def receive(self, request):
gateway_slug = request.data.get("gateway_slug") or request.query_params.get("gateway_slug")
gateway = (
PaymentGateway.objects.filter(slug=gateway_slug, is_active=True).first()
if gateway_slug
else PaymentGateway.objects.filter(is_active=True).first()
)
if gateway is None:
return Response(
{"detail": "No active payment gateway found."},
status=status.HTTP_404_NOT_FOUND,
)
from django.utils.module_loading import import_string
try:
gateway_cls = import_string(gateway.gateway_class)
gateway_instance = gateway_cls(gateway.config)
result = gateway_instance.handle_webhook(payload=request.data, headers=dict(request.headers))
except Exception as exc: # noqa: BLE001
return Response(
{"detail": f"Webhook processing failed: {exc}"},
status=status.HTTP_400_BAD_REQUEST,
)
if not result.is_handled:
return Response(
{"status": "ignored", "event_type": result.event_type},
status=status.HTTP_200_OK,
)
return Response({"status": "processed", "event_type": result.event_type, "data": result.data})