diff --git a/api/organisations/task_helpers.py b/api/organisations/task_helpers.py index 0062633322dc..80bac5d0f9e1 100644 --- a/api/organisations/task_helpers.py +++ b/api/organisations/task_helpers.py @@ -125,7 +125,7 @@ def handle_api_usage_notification_for_organisation(organisation: Organisation) - month_delta = _get_total_months(relativedelta(now, billing_starts_at)) period_starts_at = relativedelta(months=month_delta) + billing_starts_at - allowed_api_calls = subscription_cache.allowed_30d_api_calls + allowed_api_calls = organisation.subscription.max_api_calls openfeature_client = get_openfeature_client() # TODO: Default to get_total_events_count — https://github.com/Flagsmith/flagsmith/issues/6985 diff --git a/api/organisations/tasks.py b/api/organisations/tasks.py index f7a00ef62926..5951dc0c7b66 100644 --- a/api/organisations/tasks.py +++ b/api/organisations/tasks.py @@ -131,7 +131,7 @@ def handle_api_usage_notifications() -> None: # threshold in the last 30d, it must be below it for the current billing period # (which by definition is <30d). subscription_information_cache__api_calls_30d__gte=F( - "subscription_information_cache__allowed_30d_api_calls" + "subscription__max_api_calls" ) * threshold_percentage, ).select_related("subscription", "subscription_information_cache"): diff --git a/api/tests/unit/organisations/test_unit_organisations_tasks.py b/api/tests/unit/organisations/test_unit_organisations_tasks.py index d953ed2845e3..fc9ab8ff75b6 100644 --- a/api/tests/unit/organisations/test_unit_organisations_tasks.py +++ b/api/tests/unit/organisations/test_unit_organisations_tasks.py @@ -431,6 +431,7 @@ def test_handle_api_usage_notifications__usage_below_100_percent__sends_90_perce now = timezone.now() organisation.subscription.plan = SCALE_UP organisation.subscription.subscription_id = "fancy_id" + organisation.subscription.max_api_calls = 100 # Updated to fix broken test organisation.subscription.save() OrganisationSubscriptionInformationCache.objects.create( organisation=organisation, @@ -530,6 +531,61 @@ def test_handle_api_usage_notifications__usage_below_100_percent__sends_90_perce ) +@pytest.mark.freeze_time("2023-01-19T09:09:47.325132+00:00") +def test_handle_api_usage_notifications__stale_cache_lower_than_subscription_limit__sends_no_email( + mocker: MockerFixture, + organisation: Organisation, + mailoutbox: list[EmailMultiAlternatives], + enable_features: EnableFeaturesFixture, +) -> None: + # Given + now = timezone.now() + usage = 95 + stale_cache_allowance = 100 + true_subscription_allowance = 50_000 + + # 1. Set the TRUE subscription limit to 50,000 + organisation.subscription.plan = SCALE_UP + organisation.subscription.subscription_id = "fancy_id" + organisation.subscription.max_api_calls = true_subscription_allowance + organisation.subscription.save() + + # 2. Set the STALE cache limit to 100 + OrganisationSubscriptionInformationCache.objects.create( + organisation=organisation, + allowed_30d_api_calls=stale_cache_allowance, + current_billing_term_starts_at=now - timedelta(days=45), + current_billing_term_ends_at=now + timedelta(days=320), + api_calls_30d=usage, + ) + + mock_api_usage = mocker.patch( + "organisations.task_helpers.get_current_api_usage", + ) + mock_api_usage.return_value = usage + enable_features("api_usage_alerting") + + assert not OrganisationAPIUsageNotification.objects.filter( + organisation=organisation, + ).exists() + + # When + handle_api_usage_notifications() + + # Then + # Because usage (95) is evaluated against the true allowance (50,000), + # it is < 1%, so no notification should be sent. + mock_api_usage.assert_not_called() + assert len(mailoutbox) == 0 + + assert ( + OrganisationAPIUsageNotification.objects.filter( + organisation=organisation, + ).count() + == 0 + ) + + @pytest.mark.freeze_time("2023-01-19T09:09:47.325132+00:00") def test_handle_api_usage_notifications__usage_below_alert_thresholds__sends_no_email( mocker: MockerFixture, @@ -592,6 +648,7 @@ def test_handle_api_usage_notifications__usage_above_100_percent__sends_limit_no now = timezone.now() organisation.subscription.plan = SCALE_UP organisation.subscription.subscription_id = "fancy_id" + organisation.subscription.max_api_calls = allowance organisation.subscription.save() OrganisationSubscriptionInformationCache.objects.create( organisation=organisation, @@ -735,6 +792,8 @@ def test_handle_api_usage_notifications__free_account_over_limit__sends_limit_no assert organisation.is_paid is False assert organisation.subscription.is_free_plan is True assert organisation.subscription.max_api_calls == MAX_API_CALLS_IN_FREE_PLAN + organisation.subscription.max_api_calls = MAX_API_CALLS_IN_FREE_PLAN + organisation.subscription.save() OrganisationSubscriptionInformationCache.objects.create( organisation=organisation,