views.py 6.5 KB

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