Skip to content

Commit de92415

Browse files
authored
feat(billing): Remove AUTO_SEAT_UPGRADE_PLANS setting (#5343)
1 parent fdebe4f commit de92415

8 files changed

Lines changed: 67 additions & 69 deletions

File tree

api/app/settings/common.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,14 +1193,6 @@
11931193
# hubspot without a Flagsmith organisation.
11941194
CREATE_HUBSPOT_LEAD_WITHOUT_ORGANISATION_DELAY_MINUTES = 30
11951195

1196-
# List of plan ids that support seat upgrades
1197-
AUTO_SEAT_UPGRADE_PLANS = env.list(
1198-
"AUTO_SEAT_UPGRADE_PLANS",
1199-
subcast=str,
1200-
default=[],
1201-
)
1202-
1203-
12041196
SKIP_MIGRATION_TESTS = env.bool("SKIP_MIGRATION_TESTS", False)
12051197

12061198
# prevent django-softdelete from performing whole table deletes!

api/conftest.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import importlib
2+
import inspect
13
import logging
24
import os
35
import typing
@@ -19,6 +21,8 @@
1921
from flag_engine.segments.constants import EQUAL
2022
from moto import mock_dynamodb # type: ignore[import-untyped]
2123
from mypy_boto3_dynamodb.service_resource import DynamoDBServiceResource, Table
24+
from pyfakefs.fake_filesystem import FakeFilesystem
25+
from pyfakefs.fake_filesystem_unittest import Patcher
2226
from pytest_django.fixtures import SettingsWrapper
2327
from pytest_django.plugin import blocking_manager_key
2428
from pytest_mock import MockerFixture
@@ -133,6 +137,24 @@ def pytest_configure(config: pytest.Config) -> None:
133137
)
134138

135139

140+
@pytest.fixture
141+
def fs() -> typing.Generator[FakeFilesystem | None, None, None]:
142+
app_path = os.path.dirname(os.path.abspath(__file__))
143+
real_paths = [app_path]
144+
145+
for module_name in (
146+
"django",
147+
"tzdata",
148+
):
149+
module_file = inspect.getfile(importlib.import_module(module_name))
150+
real_paths.append(os.path.dirname(os.path.abspath(module_file)))
151+
152+
with Patcher() as patcher:
153+
if fs := patcher.fs:
154+
fs.add_real_paths(real_paths)
155+
yield fs
156+
157+
136158
@pytest.fixture(scope="session")
137159
def django_db_setup(request: pytest.FixtureRequest) -> None:
138160
if (

api/organisations/invites/views.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,7 @@ def perform_create(self, serializer): # type: ignore[no-untyped-def]
151151
subscription_metadata = organisation.subscription.get_subscription_metadata()
152152

153153
if (
154-
len(settings.AUTO_SEAT_UPGRADE_PLANS) > 0
155-
and organisation.num_seats >= subscription_metadata.seats
154+
organisation.num_seats >= subscription_metadata.seats
156155
and not organisation.subscription.can_auto_upgrade_seats
157156
):
158157
raise SubscriptionDoesNotSupportSeatUpgrade()

api/organisations/models.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,7 @@ def reset_alert_status(self): # type: ignore[no-untyped-def]
138138
self.save()
139139

140140
def is_auto_seat_upgrade_available(self) -> bool:
141-
return (
142-
len(settings.AUTO_SEAT_UPGRADE_PLANS) > 0
143-
and self.subscription.can_auto_upgrade_seats
144-
)
141+
return self.subscription.can_auto_upgrade_seats
145142

146143
@hook(BEFORE_DELETE)
147144
def cancel_subscription(self): # type: ignore[no-untyped-def]
@@ -262,7 +259,10 @@ def update_plan(self, plan_id): # type: ignore[no-untyped-def]
262259

263260
@property
264261
def can_auto_upgrade_seats(self) -> bool:
265-
return self.plan in settings.AUTO_SEAT_UPGRADE_PLANS
262+
return (
263+
is_saas()
264+
and self.subscription_plan_family == SubscriptionPlanFamily.SCALE_UP
265+
)
266266

267267
@property
268268
def is_free_plan(self) -> bool:

api/tests/unit/organisations/invites/test_unit_invites_views.py

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import json
2-
import typing
32
from datetime import timedelta
43

54
import pytest
@@ -14,7 +13,7 @@
1413

1514
from organisations.invites.models import Invite, InviteLink
1615
from organisations.models import Organisation, OrganisationRole, Subscription
17-
from users.models import FFAdminUser, HubspotTracker
16+
from users.models import FFAdminUser, HubspotTracker, UserPermissionGroup
1817

1918

2019
def test_create_invite_link(
@@ -184,13 +183,18 @@ def test_join_organisation_with_permission_groups( # type: ignore[no-untyped-de
184183
invite.refresh_from_db()
185184

186185

187-
def test_create_invite_with_permission_groups( # type: ignore[no-untyped-def]
188-
admin_client, organisation, user_permission_group, admin_user, subscription
189-
):
186+
@pytest.mark.saas_mode
187+
def test_create_invite_with_permission_groups(
188+
admin_client: APIClient,
189+
organisation: Organisation,
190+
user_permission_group: UserPermissionGroup,
191+
admin_user: FFAdminUser,
192+
chargebee_subscription: Subscription,
193+
) -> None:
190194
# Given
191195
# update subscription to add another seat
192-
subscription.max_seats = 2
193-
subscription.save()
196+
chargebee_subscription.max_seats = 2
197+
chargebee_subscription.save()
194198

195199
url = reverse(
196200
"api-v1:organisations:organisation-invites-list",
@@ -204,23 +208,19 @@ def test_create_invite_with_permission_groups( # type: ignore[no-untyped-def]
204208
url, data=json.dumps(data), content_type="application/json"
205209
)
206210
# Then
207-
assert response.status_code == status.HTTP_201_CREATED
211+
assert response.status_code == status.HTTP_201_CREATED, response.json()
208212
# and
209213
invite = Invite.objects.get(email=email)
210214
assert invite.permission_groups.first() == user_permission_group
211215
assert invite.invited_by == admin_user
212216

213217

214-
def test_create_invite_returns_400_if_seats_are_over( # type: ignore[no-untyped-def]
215-
admin_client,
216-
organisation,
217-
user_permission_group,
218-
admin_user,
219-
subscription,
220-
settings,
221-
):
218+
def test_create_invite_returns_400_if_seats_are_over(
219+
admin_client: APIClient,
220+
organisation: Organisation,
221+
user_permission_group: UserPermissionGroup,
222+
) -> None:
222223
# Given
223-
settings.AUTO_SEAT_UPGRADE_PLANS = ["scale-up"]
224224
url = reverse(
225225
"api-v1:organisations:organisation-invites-list",
226226
args=[organisation.pk],
@@ -288,18 +288,14 @@ def test_update_invite_returns_405( # type: ignore[no-untyped-def]
288288
(lazy_fixture("invite_link"), "api-v1:users:user-join-organisation-link"),
289289
],
290290
)
291-
def test_join_organisation_returns_400_if_exceeds_plan_limit( # type: ignore[no-untyped-def]
292-
test_user_client,
293-
organisation,
294-
admin_user,
295-
invite_object,
296-
url,
297-
subscription,
298-
settings,
299-
):
291+
def test_join_organisation_returns_400_if_exceeds_plan_limit(
292+
test_user_client: APIClient,
293+
invite_object: Invite | InviteLink,
294+
url: str,
295+
settings: SettingsWrapper,
296+
) -> None:
300297
# Given
301298
settings.ENABLE_CHARGEBEE = True
302-
settings.AUTO_SEAT_UPGRADE_PLANS = ["scale-up"]
303299
url = reverse(url, args=[invite_object.hash])
304300
# When
305301
response = test_user_client.post(url)
@@ -312,26 +308,24 @@ def test_join_organisation_returns_400_if_exceeds_plan_limit( # type: ignore[no
312308
)
313309

314310

311+
@pytest.mark.saas_mode
315312
@pytest.mark.parametrize(
316313
"invite_object, url",
317314
[
318315
(lazy_fixture("invite"), "api-v1:users:user-join-organisation"),
319316
(lazy_fixture("invite_link"), "api-v1:users:user-join-organisation-link"),
320317
],
321318
)
322-
def test_join_organisation_returns_400_if_payment_fails( # type: ignore[no-untyped-def]
319+
def test_join_organisation_returns_400_if_payment_fails(
323320
test_user_client: APIClient,
324-
organisation: Organisation,
325-
admin_user: FFAdminUser,
326-
invite_object: typing.Union[Invite, InviteLink],
321+
invite_object: Invite | InviteLink,
327322
url: str,
328323
subscription: Subscription,
329324
settings: SettingsWrapper,
330325
mocker: MockerFixture,
331-
):
326+
) -> None:
332327
# Given
333328
settings.ENABLE_CHARGEBEE = True
334-
settings.AUTO_SEAT_UPGRADE_PLANS = ["scale-up"]
335329

336330
url = reverse(url, args=[invite_object.hash])
337331

api/tests/unit/organisations/test_unit_organisations_models.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,13 @@ def test_organisation_over_plan_seats_no_subscription(organisation, mocker, admi
168168
mocked_get_subscription_metadata.assert_not_called()
169169

170170

171-
def test_organisation_is_auto_seat_upgrade_available(organisation, settings): # type: ignore[no-untyped-def]
171+
@pytest.mark.saas_mode
172+
def test_organisation_is_auto_seat_upgrade_available(
173+
organisation: Organisation,
174+
) -> None:
172175
# Given
173176
plan = "Scale-Up"
174177
subscription_id = "subscription-id"
175-
settings.AUTO_SEAT_UPGRADE_PLANS = [plan]
176178

177179
Subscription.objects.filter(organisation=organisation).update(
178180
subscription_id=subscription_id, plan=plan
@@ -413,12 +415,11 @@ def test_organisation_get_subscription_metadata_for_self_hosted_open_source(
413415
assert subscription_metadata == FREE_PLAN_SUBSCRIPTION_METADATA
414416

415417

416-
def test_organisation_subscription_add_single_seat_calls_correct_chargebee_method_for_upgradable_plan( # type: ignore[no-untyped-def] # noqa: E501
417-
mocker, settings
418-
):
418+
@pytest.mark.saas_mode
419+
def test_organisation_subscription_add_single_seat_calls_correct_chargebee_method_for_upgradable_plan( # noqa: E501
420+
mocker: MockerFixture,
421+
) -> None:
419422
# Given
420-
settings.AUTO_SEAT_UPGRADE_PLANS = ["scale-up"]
421-
422423
subscription_id = "subscription-id"
423424
subscription = Subscription(subscription_id=subscription_id, plan="scale-up")
424425

@@ -432,12 +433,10 @@ def test_organisation_subscription_add_single_seat_calls_correct_chargebee_metho
432433
mocked_add_single_seat.assert_called_once_with(subscription_id)
433434

434435

435-
def test_organisation_subscription_add_single_seat_raises_error_for_non_upgradable_plan( # type: ignore[no-untyped-def] # noqa: E501
436-
mocker, settings
437-
):
436+
def test_organisation_subscription_add_single_seat_raises_error_for_non_upgradable_plan( # noqa: E501
437+
mocker: MockerFixture,
438+
) -> None:
438439
# Given
439-
settings.AUTO_SEAT_UPGRADE_PLANS = ["scale-up"]
440-
441440
subscription_id = "subscription-id"
442441
subscription = Subscription(
443442
subscription_id=subscription_id, plan="not-a-scale-up-plan"

infrastructure/aws/production/ecs-task-definition-web.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,6 @@
187187
"name": "ENABLE_PIPEDRIVE_LEAD_TRACKING",
188188
"value": "True"
189189
},
190-
{
191-
"name": "AUTO_SEAT_UPGRADE_PLANS",
192-
"value": "scale-up-12-months-v2-gbp,scale-up-12-months-v2-eur,scale-up-12-months-v2,scale-up-quarterly-v2-semiannual,scale-up-quarterly-v2,scale-up-v2,scale-up-24-months-v2"
193-
},
194190
{
195191
"name": "PIPEDRIVE_IGNORE_DOMAINS",
196192
"value": "flagsmith.com,solidstategroup.com,restmail.net,bullettrain.io,flagsmithe2etestdomain.io"
@@ -281,4 +277,4 @@
281277
],
282278
"cpu": "1024",
283279
"memory": "2048"
284-
}
280+
}

infrastructure/aws/staging/ecs-task-definition-web.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,6 @@
163163
"name": "ENABLE_PIPEDRIVE_LEAD_TRACKING",
164164
"value": "True"
165165
},
166-
{
167-
"name": "AUTO_SEAT_UPGRADE_PLANS",
168-
"value": "scale-up,scale-up-v2,scale-up-annual-v2,scale-up-24-months-v2"
169-
},
170166
{
171167
"name": "USE_POSTGRES_FOR_ANALYTICS",
172168
"value": "False"

0 commit comments

Comments
 (0)