Skip to content

Commit

Permalink
feat: trial management in sales dashboard (#2805)
Browse files Browse the repository at this point in the history
Co-authored-by: Matthew Elwell <[email protected]>
  • Loading branch information
dabeeeenster and matthewelwell authored Nov 13, 2023
1 parent 7e1c779 commit a056713
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 3 deletions.
5 changes: 4 additions & 1 deletion api/organisations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down Expand Up @@ -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)
Expand Down
43 changes: 42 additions & 1 deletion api/sales_dashboard/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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()

Expand Down
15 changes: 15 additions & 0 deletions api/sales_dashboard/templates/sales_dashboard/organisation.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ <h2>
</tr>
</tbody>
</table>
{%if organisation.subscription.is_in_trial %}
<form action="{% url 'sales_dashboard:organisation_end_trial' organisation.id %}" method="post" class="form-inline float-right">
{% csrf_token %}
<button type="submit" class="btn btn-primary mb-2">End Trial</button>
</form>
{% else %}
<form action="{% url 'sales_dashboard:organisation_start_trial' organisation.id %}" method="post" class="form-inline float-right">
{% csrf_token %}
<label class="sr-only" for="trialSeats">Seats</label>
<input type="text" class="form-control mb-2 mr-sm-2" id="max_seats" name="max_seats" placeholder="Seats">
<label class="sr-only" for="trialApiCalls">API Calls</label>
<input type="text" class="form-control mb-2 mr-sm-2" id="max_api_calls" name="max_api_calls" placeholder="API Calls">
<button type="submit" class="btn btn-primary mb-2">Start Trial</button>
</form>
{% endif %}
</div>

<h2>Projects</h2>
Expand Down
10 changes: 10 additions & 0 deletions api/sales_dashboard/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
views.update_seats,
name="update_seats",
),
path(
"organisations/<int:organisation_id>/organisation_start_trial",
views.organisation_start_trial,
name="organisation_start_trial",
),
path(
"organisations/<int:organisation_id>/organisation_end_trial",
views.organisation_end_trial,
name="organisation_end_trial",
),
path(
"organisations/<int:project_id>/migrate_identities",
views.migrate_identities_to_edge,
Expand Down
41 changes: 40 additions & 1 deletion api/sales_dashboard/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit a056713

Please sign in to comment.