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})