diff --git a/api/organisations/models.py b/api/organisations/models.py index 70ec225e768c..b8161045ac36 100644 --- a/api/organisations/models.py +++ b/api/organisations/models.py @@ -228,7 +228,7 @@ def get_portal_url(self, redirect_url): def get_subscription_metadata(self) -> BaseSubscriptionMetadata: metadata = None - if self.subscription_id == TRIAL_SUBSCRIPTION_ID: + if self.is_in_trial(): metadata = BaseSubscriptionMetadata( seats=self.max_seats, api_calls=self.max_api_calls ) @@ -272,6 +272,9 @@ def get_api_call_overage(self): ) return overage if overage > 0 else 0 + def is_in_trial(self) -> bool: + return self.subscription_id == TRIAL_SUBSCRIPTION_ID + class OrganisationWebhook(AbstractBaseExportableWebhookModel): name = models.CharField(max_length=100) diff --git a/api/sales_dashboard/forms.py b/api/sales_dashboard/forms.py index 4878180b056b..b14b2bcbf2b7 100644 --- a/api/sales_dashboard/forms.py +++ b/api/sales_dashboard/forms.py @@ -7,7 +7,12 @@ from environments.models import Environment from features.models import Feature -from organisations.models import Organisation +from organisations.models import TRIAL_SUBSCRIPTION_ID, Organisation +from organisations.subscriptions.constants import ( + FREE_PLAN_ID, + MAX_API_CALLS_IN_FREE_PLAN, + MAX_SEATS_IN_FREE_PLAN, +) from projects.models import Project from users.models import FFAdminUser @@ -28,6 +33,42 @@ def save(self, organisation, commit=True): organisation.subscription.save() +class StartTrialForm(forms.Form): + max_seats = forms.IntegerField() + max_api_calls = forms.IntegerField() + + def save(self, organisation: Organisation, commit: bool = True) -> Organisation: + subscription = organisation.subscription + + subscription.max_seats = self.cleaned_data["max_seats"] + subscription.max_api_calls = self.cleaned_data["max_api_calls"] + subscription.subscription_id = TRIAL_SUBSCRIPTION_ID + subscription.customer_id = TRIAL_SUBSCRIPTION_ID + subscription.plan = "enterprise-saas-monthly-v2" + + if commit: + subscription.save() + + return organisation + + +class EndTrialForm(forms.Form): + def save(self, organisation: Organisation, commit: bool = True) -> Organisation: + subscription = organisation.subscription + + subscription.max_seats = MAX_SEATS_IN_FREE_PLAN + subscription.max_api_calls = MAX_API_CALLS_IN_FREE_PLAN + subscription.subscription_id = "" + subscription.customer_id = "" + subscription.plan = FREE_PLAN_ID + subscription.save() + + if commit: + subscription.save() + + return organisation + + class EmailUsageForm(forms.Form): email_address = forms.EmailField() diff --git a/api/sales_dashboard/templates/sales_dashboard/organisation.html b/api/sales_dashboard/templates/sales_dashboard/organisation.html index 305468b8e1d1..208626b08840 100644 --- a/api/sales_dashboard/templates/sales_dashboard/organisation.html +++ b/api/sales_dashboard/templates/sales_dashboard/organisation.html @@ -81,6 +81,21 @@

+ {%if organisation.subscription.is_in_trial %} +
+ {% csrf_token %} + +
+ {% else %} +
+ {% csrf_token %} + + + + + +
+ {% endif %}

Projects

diff --git a/api/sales_dashboard/urls.py b/api/sales_dashboard/urls.py index ffd53040684c..024edb4fb3f0 100644 --- a/api/sales_dashboard/urls.py +++ b/api/sales_dashboard/urls.py @@ -18,6 +18,16 @@ views.update_seats, name="update_seats", ), + path( + "organisations//organisation_start_trial", + views.organisation_start_trial, + name="organisation_start_trial", + ), + path( + "organisations//organisation_end_trial", + views.organisation_end_trial, + name="organisation_end_trial", + ), path( "organisations//migrate_identities", views.migrate_identities_to_edge, diff --git a/api/sales_dashboard/views.py b/api/sales_dashboard/views.py index a3ab59f63e7f..739a03dc4648 100644 --- a/api/sales_dashboard/views.py +++ b/api/sales_dashboard/views.py @@ -9,6 +9,7 @@ from django.core.serializers.json import DjangoJSONEncoder from django.db.models import Count, F, Q from django.http import ( + HttpRequest, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect, @@ -36,7 +37,13 @@ update_organisation_subscription_information_influx_cache, ) -from .forms import EmailUsageForm, MaxAPICallsForm, MaxSeatsForm +from .forms import ( + EmailUsageForm, + EndTrialForm, + MaxAPICallsForm, + MaxSeatsForm, + StartTrialForm, +) OBJECTS_PER_PAGE = 50 DEFAULT_ORGANISATION_SORT = "subscription_information_cache__api_calls_30d" @@ -185,6 +192,38 @@ def update_max_api_calls(request, organisation_id): return HttpResponseRedirect(reverse("sales_dashboard:index")) +@staff_member_required +def organisation_start_trial( + request: HttpRequest, organisation_id: int +) -> HttpResponse: + start_trial_form = StartTrialForm(request.POST) + if start_trial_form.is_valid(): + organisation = get_object_or_404(Organisation, pk=organisation_id) + start_trial_form.save(organisation) + + return HttpResponseRedirect( + reverse( + "sales_dashboard:organisation_info", + kwargs={"organisation_id": organisation_id}, + ) + ) + + +@staff_member_required +def organisation_end_trial(request: HttpRequest, organisation_id: int) -> HttpResponse: + end_trial_form = EndTrialForm(request.POST) + if end_trial_form.is_valid(): + organisation = get_object_or_404(Organisation, pk=organisation_id) + end_trial_form.save(organisation) + + return HttpResponseRedirect( + reverse( + "sales_dashboard:organisation_info", + kwargs={"organisation_id": organisation_id}, + ) + ) + + @staff_member_required def migrate_identities_to_edge(request, project_id): if not settings.PROJECT_METADATA_TABLE_NAME_DYNAMO: