views.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. from django.conf import settings
  2. from django.core.cache import cache
  3. from django.http import Http404
  4. from rest_framework import viewsets, views, status
  5. from rest_framework.decorators import action
  6. from rest_framework.response import Response
  7. from drf_yasg.utils import swagger_auto_schema
  8. from djstripe.models import Subscription, Customer, Product
  9. from djstripe.settings import STRIPE_SECRET_KEY
  10. import stripe
  11. from events.models import Event
  12. from performance.models import TransactionEvent
  13. from .serializers import (
  14. SubscriptionSerializer,
  15. CreateSubscriptionSerializer,
  16. PlanForOrganizationSerializer,
  17. OrganizationSelectSerializer,
  18. ProductSerializer,
  19. )
  20. class SubscriptionViewSet(viewsets.ModelViewSet):
  21. """
  22. View subscription status and create new free tier subscriptions
  23. Use organization slug for detail view. Ex: /subscriptions/my-cool-org/
  24. """
  25. queryset = Subscription.objects.all()
  26. serializer_class = SubscriptionSerializer
  27. lookup_field = "customer__subscriber__slug"
  28. def get_serializer_class(self):
  29. if self.action == "create":
  30. return CreateSubscriptionSerializer
  31. return super().get_serializer_class()
  32. def get_queryset(self):
  33. """ Any user in an org may view subscription data """
  34. if self.request.user.is_authenticated:
  35. return self.queryset.filter(
  36. livemode=settings.STRIPE_LIVE_MODE,
  37. customer__subscriber__users=self.request.user,
  38. )
  39. return self.queryset.none()
  40. def get_object(self):
  41. """ Get most recent by slug """
  42. try:
  43. return (
  44. self.get_queryset().filter(**self.kwargs).order_by("-created").first()
  45. )
  46. except Subscription.DoesNotExist:
  47. raise Http404
  48. @action(detail=True, methods=["get"])
  49. def events_count(self, *args, **kwargs):
  50. """ Get event count for current billing period """
  51. subscription = self.get_object()
  52. if not subscription:
  53. return Response(0)
  54. organization = subscription.customer.subscriber
  55. cache_key = "org_event_count" + str(organization.pk)
  56. cached_total = cache.get(cache_key)
  57. if cached_total is not None:
  58. return Response(cached_total)
  59. event_count = Event.objects.filter(
  60. issue__project__organization=organization,
  61. created__gte=subscription.current_period_start,
  62. created__lt=subscription.current_period_end,
  63. ).count()
  64. transaction_event_count = TransactionEvent.objects.filter(
  65. project__organization=organization,
  66. created__gte=subscription.current_period_start,
  67. created__lt=subscription.current_period_end,
  68. ).count()
  69. total = event_count + transaction_event_count
  70. cache.set(cache_key, total, 600)
  71. return Response(total)
  72. class ProductViewSet(viewsets.ReadOnlyModelViewSet):
  73. queryset = Product.objects.filter(
  74. active=True, livemode=settings.STRIPE_LIVE_MODE, plan__active=True
  75. ).prefetch_related("plan_set")
  76. serializer_class = ProductSerializer
  77. class CreateStripeSubscriptionCheckout(views.APIView):
  78. """ Create Stripe Checkout, send to client for redirecting to Stripe """
  79. def get_serializer(self, *args, **kwargs):
  80. return PlanForOrganizationSerializer(
  81. data=self.request.data, context={"request": self.request}
  82. )
  83. @swagger_auto_schema(
  84. responses={200: str(stripe.api_resources.checkout.session.Session)}
  85. )
  86. def post(self, request):
  87. """ See https://stripe.com/docs/api/checkout/sessions/create """
  88. serializer = self.get_serializer()
  89. if serializer.is_valid():
  90. organization = serializer.validated_data["organization"]
  91. customer, _ = Customer.get_or_create(subscriber=organization)
  92. domain = settings.GLITCHTIP_DOMAIN.geturl()
  93. session = stripe.checkout.Session.create(
  94. api_key=STRIPE_SECRET_KEY,
  95. payment_method_types=["card"],
  96. line_items=[
  97. {"price": serializer.validated_data["plan"].id, "quantity": 1,}
  98. ],
  99. mode="subscription",
  100. customer=customer.id,
  101. success_url=domain
  102. + "/"
  103. + organization.slug
  104. + "/settings/subscription?session_id={CHECKOUT_SESSION_ID}",
  105. cancel_url=domain + "",
  106. )
  107. return Response(session)
  108. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  109. class StripeBillingPortal(views.APIView):
  110. def get_serializer(self, *args, **kwargs):
  111. return OrganizationSelectSerializer(
  112. data=self.request.data, context={"request": self.request}
  113. )
  114. @swagger_auto_schema(
  115. responses={200: str(stripe.api_resources.billing_portal.Session)}
  116. )
  117. def post(self, request):
  118. """ See https://stripe.com/docs/billing/subscriptions/integrating-self-serve-portal """
  119. serializer = self.get_serializer()
  120. if serializer.is_valid():
  121. organization = serializer.validated_data["organization"]
  122. customer, _ = Customer.get_or_create(subscriber=organization)
  123. domain = settings.GLITCHTIP_DOMAIN.geturl()
  124. session = stripe.billing_portal.Session.create(
  125. api_key=STRIPE_SECRET_KEY,
  126. customer=customer.id,
  127. return_url=domain + "/" + organization.slug + "/settings/subscription",
  128. )
  129. return Response(session)
  130. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)