views.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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 djstripe_settings
  10. import stripe
  11. from organizations_ext.models import Organization
  12. from events.models import Event
  13. from performance.models import TransactionEvent
  14. from glitchtip.uptime.models import MonitorCheck
  15. from .serializers import (
  16. SubscriptionSerializer,
  17. CreateSubscriptionSerializer,
  18. PlanForOrganizationSerializer,
  19. OrganizationSelectSerializer,
  20. ProductSerializer,
  21. )
  22. class SubscriptionViewSet(viewsets.ModelViewSet):
  23. """
  24. View subscription status and create new free tier subscriptions
  25. Use organization slug for detail view. Ex: /subscriptions/my-cool-org/
  26. """
  27. queryset = Subscription.objects.all()
  28. serializer_class = SubscriptionSerializer
  29. lookup_field = "customer__subscriber__slug"
  30. def get_serializer_class(self):
  31. if self.action == "create":
  32. return CreateSubscriptionSerializer
  33. return super().get_serializer_class()
  34. def get_queryset(self):
  35. """ Any user in an org may view subscription data """
  36. if self.request.user.is_authenticated:
  37. return self.queryset.filter(
  38. livemode=settings.STRIPE_LIVE_MODE,
  39. customer__subscriber__users=self.request.user,
  40. )
  41. return self.queryset.none()
  42. def get_object(self):
  43. """ Get most recent by slug """
  44. try:
  45. subscription = (
  46. self.get_queryset().filter(**self.kwargs).order_by("-created").first()
  47. )
  48. # Check organization throttle, in case it changed recently
  49. if subscription:
  50. Organization.objects.filter(
  51. id=subscription.customer.subscriber_id,
  52. is_accepting_events=False,
  53. is_active=True,
  54. djstripe_customers__subscriptions__plan__amount__gt=0,
  55. djstripe_customers__subscriptions__status="active",
  56. ).update(is_accepting_events=True)
  57. return subscription
  58. except Subscription.DoesNotExist:
  59. raise Http404
  60. @action(detail=True, methods=["get"])
  61. def events_count(self, *args, **kwargs):
  62. """ Get event count for current billing period """
  63. subscription = self.get_object()
  64. if not subscription:
  65. return Response(
  66. {
  67. "eventCount": 0,
  68. "transactionEventCount": 0,
  69. "uptimeCheckEventCount": 0,
  70. }
  71. )
  72. organization = subscription.customer.subscriber
  73. cache_key = "org_event_count" + str(organization.pk)
  74. data = cache.get(cache_key)
  75. if data is None:
  76. event_count = Event.objects.filter(
  77. issue__project__organization=organization,
  78. created__gte=subscription.current_period_start,
  79. created__lt=subscription.current_period_end,
  80. ).count()
  81. transaction_event_count = TransactionEvent.objects.filter(
  82. group__project__organization=organization,
  83. created__gte=subscription.current_period_start,
  84. created__lt=subscription.current_period_end,
  85. ).count()
  86. uptime_check_event_count = MonitorCheck.objects.filter(
  87. monitor__organization=organization,
  88. created__gte=subscription.current_period_start,
  89. created__lt=subscription.current_period_end,
  90. ).count()
  91. data = {
  92. "eventCount": event_count,
  93. "transactionEventCount": transaction_event_count,
  94. "uptimeCheckEventCount": uptime_check_event_count,
  95. }
  96. cache.set(cache_key, data, 600)
  97. return Response(data)
  98. class ProductViewSet(viewsets.ReadOnlyModelViewSet):
  99. queryset = Product.objects.filter(
  100. active=True,
  101. livemode=settings.STRIPE_LIVE_MODE,
  102. plan__active=True,
  103. metadata__events__isnull=False,
  104. ).prefetch_related("plan_set")
  105. serializer_class = ProductSerializer
  106. class CreateStripeSubscriptionCheckout(views.APIView):
  107. """ Create Stripe Checkout, send to client for redirecting to Stripe """
  108. def get_serializer(self, *args, **kwargs):
  109. return PlanForOrganizationSerializer(
  110. data=self.request.data, context={"request": self.request}
  111. )
  112. @swagger_auto_schema(
  113. responses={200: str(stripe.api_resources.checkout.session.Session)}
  114. )
  115. def post(self, request):
  116. """ See https://stripe.com/docs/api/checkout/sessions/create """
  117. serializer = self.get_serializer()
  118. if serializer.is_valid():
  119. organization = serializer.validated_data["organization"]
  120. customer, _ = Customer.get_or_create(subscriber=organization)
  121. domain = settings.GLITCHTIP_URL.geturl()
  122. session = stripe.checkout.Session.create(
  123. api_key=djstripe_settings.STRIPE_SECRET_KEY,
  124. payment_method_types=["card"],
  125. line_items=[
  126. {"price": serializer.validated_data["plan"].id, "quantity": 1,}
  127. ],
  128. mode="subscription",
  129. customer=customer.id,
  130. automatic_tax={"enabled": settings.STRIPE_AUTOMATIC_TAX,},
  131. customer_update={"address": "auto", "name": "auto"},
  132. tax_id_collection={"enabled": True,},
  133. success_url=domain
  134. + "/"
  135. + organization.slug
  136. + "/settings/subscription?session_id={CHECKOUT_SESSION_ID}",
  137. cancel_url=domain + "",
  138. )
  139. return Response(session)
  140. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  141. class StripeBillingPortal(views.APIView):
  142. def get_serializer(self, *args, **kwargs):
  143. return OrganizationSelectSerializer(
  144. data=self.request.data, context={"request": self.request}
  145. )
  146. @swagger_auto_schema(
  147. responses={200: str(stripe.api_resources.billing_portal.Session)}
  148. )
  149. def post(self, request):
  150. """ See https://stripe.com/docs/billing/subscriptions/integrating-self-serve-portal """
  151. serializer = self.get_serializer()
  152. if serializer.is_valid():
  153. organization = serializer.validated_data["organization"]
  154. customer, _ = Customer.get_or_create(subscriber=organization)
  155. domain = settings.GLITCHTIP_URL.geturl()
  156. session = stripe.billing_portal.Session.create(
  157. api_key=djstripe_settings.STRIPE_SECRET_KEY,
  158. customer=customer.id,
  159. return_url=domain + "/" + organization.slug + "/settings/subscription",
  160. )
  161. return Response(session)
  162. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)