Skip to content
5 changes: 0 additions & 5 deletions api/app/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1389,11 +1389,6 @@
default=[],
)

# Date on which versioning is released. This is used to give any scale up
# subscriptions created before this date full audit log and versioning
# history.
VERSIONING_RELEASE_DATE = env.date("VERSIONING_RELEASE_DATE", default=None)

SUBSCRIPTION_LICENCE_PUBLIC_KEY = env.str(
"SUBSCRIPTION_LICENCE_PUBLIC_KEY",
"""
Expand Down
20 changes: 10 additions & 10 deletions api/organisations/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
from datetime import timedelta
from typing import Any

Expand Down Expand Up @@ -294,6 +295,11 @@ def subscription_plan_family(self) -> SubscriptionPlanFamily:
def is_enterprise(self) -> bool:
return self.subscription_plan_family == SubscriptionPlanFamily.ENTERPRISE

def get_scaleup_plan_version(self) -> int:
if match := re.match(r"scale-up-v(\d+)", self.plan or ""):
return int(match.group(1))
return 1

@hook(AFTER_SAVE, when="plan", has_changed=True)
def update_api_limit_access_block(self): # type: ignore[no-untyped-def]
if not getattr(self.organisation, "api_limit_access_block", None):
Expand Down Expand Up @@ -419,17 +425,11 @@ def _get_subscription_metadata_for_chargebee(self) -> ChargebeeObjMetadata:
else:
cb_metadata = get_subscription_metadata_from_id(self.subscription_id) # type: ignore[assignment,arg-type]

if self.subscription_plan_family == SubscriptionPlanFamily.SCALE_UP and (
settings.VERSIONING_RELEASE_DATE is None
or (
self.subscription_date is not None
and self.subscription_date < settings.VERSIONING_RELEASE_DATE
)
):
# Logic to grandfather old scale up plan customers to give them
# full access to audit log and feature history.
# Pre-v4 Scale-Up customers keep unlimited audit log. Feature
# history always honours the cache value.
is_scale_up = self.subscription_plan_family == SubscriptionPlanFamily.SCALE_UP
if is_scale_up and self.get_scaleup_plan_version() < 4:
cb_metadata.audit_log_visibility_days = None
cb_metadata.feature_history_visibility_days = None

return cb_metadata

Expand Down
90 changes: 74 additions & 16 deletions api/tests/unit/organisations/test_unit_organisations_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,35 @@ def test_is_auto_seat_upgrade_available__given_plan_and_seat_count__returns_expe
assert result is expected


@pytest.mark.parametrize(
"plan, expected_version",
[
("scale-up-v4-monthly", 4),
("scale-up-v4", 4),
("scale-up-v2", 2),
("scale-up-v10-annual", 10),
("scale-up", 1),
("startup-v2", 1),
(None, 1),
],
)
def test_get_scaleup_plan_version__given_plan__returns_expected(
organisation: Organisation,
plan: str | None,
expected_version: int,
) -> None:
# Given
subscription = organisation.subscription
subscription.plan = plan
subscription.save()

# When
version = subscription.get_scaleup_plan_version()

# Then
assert version == expected_version


def test_is_auto_seat_upgrade_available__not_saas__returns_false(
organisation: Organisation,
) -> None:
Expand Down Expand Up @@ -299,15 +328,12 @@ def test_is_paid__cancelled_subscription__returns_false( # type: ignore[no-unty
def test_get_subscription_metadata__chargebee_subscription__returns_chargebee_metadata( # type: ignore[no-untyped-def]
organisation: Organisation,
mocker: MockerFixture,
settings: SettingsWrapper,
):
# Given
seats = 10
api_calls = 50000000
projects = 10

settings.VERSIONING_RELEASE_DATE = timezone.now() - timedelta(days=1)

OrganisationSubscriptionInformationCache.objects.create(
organisation=organisation,
allowed_seats=seats,
Expand All @@ -319,7 +345,7 @@ def test_get_subscription_metadata__chargebee_subscription__returns_chargebee_me
)
mocker.patch("organisations.models.is_saas", return_value=True)
Subscription.objects.filter(organisation=organisation).update(
plan="scale-up-v2",
plan="scale-up-v4-monthly",
subscription_id="subscription-id",
payment_method=CHARGEBEE,
)
Expand All @@ -332,47 +358,79 @@ def test_get_subscription_metadata__chargebee_subscription__returns_chargebee_me
assert subscription_metadata == expected_metadata


def test_get_subscription_metadata__after_versioning_release__returns_unlimited_audit_and_versions( # type: ignore[no-untyped-def] # noqa: E501
def test_get_subscription_metadata__scale_up_v2_plan__keeps_unlimited_audit_log_only( # type: ignore[no-untyped-def] # noqa: E501
organisation: Organisation,
mocker: MockerFixture,
settings: SettingsWrapper,
):
# Given
seats = 10
api_calls = 50000000
projects = 10
now = timezone.now()
yesterday = now - timedelta(days=1)
two_days_ago = now - timedelta(days=2)
feature_history_visibility_days = 14

OrganisationSubscriptionInformationCache.objects.create(
organisation=organisation,
allowed_seats=seats,
allowed_30d_api_calls=api_calls,
allowed_projects=projects,
# values from here should be overridden
audit_log_visibility_days=30,
feature_history_visibility_days=30,
feature_history_visibility_days=feature_history_visibility_days,
)
expected_metadata = ChargebeeObjMetadata(
seats=seats,
api_calls=api_calls,
projects=projects,
# the following values are patched on based on the
# VERSIONING_RELEASE_DATE setting
audit_log_visibility_days=None,
feature_history_visibility_days=None,
feature_history_visibility_days=feature_history_visibility_days,
)
mocker.patch("organisations.models.is_saas", return_value=True)
Subscription.objects.filter(organisation=organisation).update(
plan="scale-up-v2",
subscription_id="subscription-id",
payment_method=CHARGEBEE,
subscription_date=two_days_ago,
)
organisation.subscription.refresh_from_db()

settings.VERSIONING_RELEASE_DATE = yesterday
# When
subscription_metadata = organisation.subscription.get_subscription_metadata()

# Then
assert subscription_metadata == expected_metadata


def test_get_subscription_metadata__scale_up_v4_plan__returns_cache_visibility_values( # type: ignore[no-untyped-def]
organisation: Organisation,
mocker: MockerFixture,
):
# Given
seats = 10
api_calls = 50000000
projects = 10
audit_log_visibility_days = 14
feature_history_visibility_days = 14

OrganisationSubscriptionInformationCache.objects.create(
organisation=organisation,
allowed_seats=seats,
allowed_30d_api_calls=api_calls,
allowed_projects=projects,
audit_log_visibility_days=audit_log_visibility_days,
feature_history_visibility_days=feature_history_visibility_days,
)
expected_metadata = ChargebeeObjMetadata(
seats=seats,
api_calls=api_calls,
projects=projects,
audit_log_visibility_days=audit_log_visibility_days,
feature_history_visibility_days=feature_history_visibility_days,
)
mocker.patch("organisations.models.is_saas", return_value=True)
Subscription.objects.filter(organisation=organisation).update(
plan="scale-up-v4-monthly",
subscription_id="subscription-id",
payment_method=CHARGEBEE,
)
organisation.subscription.refresh_from_db()

# When
subscription_metadata = organisation.subscription.get_subscription_metadata()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,6 @@ def test_get_subscription_metadata__cache_exists__returns_cached_data(
expected_api_calls = 100
expected_chargebee_email = "test@example.com"

settings.VERSIONING_RELEASE_DATE = timezone.now() - timedelta(days=1)
expected_feature_history_visibility_days = 30
expected_audit_log_visibility_days = 30

Expand Down Expand Up @@ -1096,7 +1095,6 @@ def test_get_subscription_metadata__no_cache__fetches_from_chargebee(
expected_api_calls = 100
expected_chargebee_email = "test@example.com"

settings.VERSIONING_RELEASE_DATE = timezone.now() - timedelta(days=1)
expected_feature_history_visibility_days = DEFAULT_VERSION_LIMIT_DAYS
expected_audit_log_visibility_days = 0

Expand Down
Loading