From 0cfb5e94668ee18370e83001bcd8b83f3c936a50 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 17 Jan 2023 14:17:35 -0500 Subject: [PATCH] Subscriptions: allow users to create a new subs on `incomplete_expired` --- readthedocs/subscriptions/constants.py | 9 ++++++ .../subscriptions/subscription_detail.html | 2 +- readthedocs/subscriptions/tests/test_views.py | 28 ++++++++++++------- readthedocs/subscriptions/views.py | 4 ++- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/readthedocs/subscriptions/constants.py b/readthedocs/subscriptions/constants.py index ce2270e49bd..1624a90760c 100644 --- a/readthedocs/subscriptions/constants.py +++ b/readthedocs/subscriptions/constants.py @@ -1,4 +1,13 @@ """Constants for subscriptions.""" +from djstripe.enums import SubscriptionStatus # Days after the subscription has ended to disable the organization DISABLE_AFTER_DAYS = 30 + +# These status are "terminal", meaning the subscription can't be updated. +# Users need to create a new subscription to use our service. +# https://stripe.com/docs/api/subscriptions/object#subscription_object-status. +TERMINAL_STRIPE_STATUS = [ + SubscriptionStatus.canceled, + SubscriptionStatus.incomplete_expired, +] diff --git a/readthedocs/subscriptions/templates/subscriptions/subscription_detail.html b/readthedocs/subscriptions/templates/subscriptions/subscription_detail.html index 1ec8f6009ae..33817d4f7b7 100644 --- a/readthedocs/subscriptions/templates/subscriptions/subscription_detail.html +++ b/readthedocs/subscriptions/templates/subscriptions/subscription_detail.html @@ -26,7 +26,7 @@ {% endif %} - {% if stripe_subscription.status != 'canceled' %} + {% if stripe_subscription.status not in terminal_stripe_status %}
{% trans "Plan" %}:
diff --git a/readthedocs/subscriptions/tests/test_views.py b/readthedocs/subscriptions/tests/test_views.py index 61d280cab7f..0d6a1351644 100644 --- a/readthedocs/subscriptions/tests/test_views.py +++ b/readthedocs/subscriptions/tests/test_views.py @@ -173,13 +173,21 @@ def test_user_without_subscription_and_customer( customer_retrieve_mock.assert_not_called() def test_user_with_canceled_subscription(self): - self.subscription.status = 'canceled' - self.stripe_subscription.status = SubscriptionStatus.canceled - self.stripe_subscription.save() - self.subscription.save() - resp = self.client.get(reverse('subscription_detail', args=[self.organization.slug])) - self.assertEqual(resp.status_code, 200) - self.assertEqual(resp.context["stripe_subscription"], self.stripe_subscription) - # The Manage Subscription form isn't shown, but the Subscribe is. - self.assertNotContains(resp, 'Manage Subscription') - self.assertContains(resp, 'Create Subscription') + for status in [ + SubscriptionStatus.canceled, + SubscriptionStatus.incomplete_expired, + ]: + self.subscription.status = status + self.stripe_subscription.status = status + self.stripe_subscription.save() + self.subscription.save() + resp = self.client.get( + reverse("subscription_detail", args=[self.organization.slug]) + ) + self.assertEqual(resp.status_code, 200) + self.assertEqual( + resp.context["stripe_subscription"], self.stripe_subscription + ) + # The Manage Subscription form isn't shown, but the Subscribe is. + self.assertNotContains(resp, "Manage Subscription") + self.assertContains(resp, "Create Subscription") diff --git a/readthedocs/subscriptions/views.py b/readthedocs/subscriptions/views.py index a49d74aae2e..dfd124870b5 100644 --- a/readthedocs/subscriptions/views.py +++ b/readthedocs/subscriptions/views.py @@ -14,6 +14,7 @@ from vanilla import DetailView, GenericView from readthedocs.organizations.views.base import OrganizationMixin +from readthedocs.subscriptions.constants import TERMINAL_STRIPE_STATUS from readthedocs.subscriptions.forms import PlanForm from readthedocs.subscriptions.models import Plan from readthedocs.subscriptions.utils import get_or_create_stripe_customer @@ -62,7 +63,7 @@ def redirect_to_checkout(self, form): stripe_subscription = self.get_object() if ( not stripe_subscription - or stripe_subscription.status != SubscriptionStatus.canceled + or stripe_subscription.status not in TERMINAL_STRIPE_STATUS ): raise Http404() @@ -113,6 +114,7 @@ def get_object(self): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) + context["terminal_stripe_status"] = TERMINAL_STRIPE_STATUS stripe_subscription = self.get_object() if stripe_subscription: context[