diff --git a/api/organisations/task_helpers.py b/api/organisations/task_helpers.py index d2984113afe4..6f304533efa1 100644 --- a/api/organisations/task_helpers.py +++ b/api/organisations/task_helpers.py @@ -97,9 +97,12 @@ def _send_api_usage_notification( def handle_api_usage_notification_for_organisation(organisation: Organisation) -> None: now = timezone.now() - if organisation.subscription.is_free_plan: + if ( + organisation.subscription.is_free_plan + or organisation.subscription.cancellation_date is not None + ): allowed_api_calls = organisation.subscription.max_api_calls - # Default to a rolling month for free accounts + # Default to a rolling month for free accounts or canceled subscriptions. days = 30 period_starts_at = now - timedelta(days) elif not organisation.has_subscription_information_cache(): diff --git a/api/organisations/tasks.py b/api/organisations/tasks.py index 510aaa2d287a..6fd888aefd03 100644 --- a/api/organisations/tasks.py +++ b/api/organisations/tasks.py @@ -191,7 +191,8 @@ def charge_for_api_call_count_overages(): - month_window_end, ) .exclude( - subscription__plan=FREE_PLAN_ID, + Q(subscription__plan=FREE_PLAN_ID) + | Q(subscription__cancellation_date__isnull=False), ) .select_related( "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 179f55c21bb9..760c8135d82f 100644 --- a/api/tests/unit/organisations/test_unit_organisations_tasks.py +++ b/api/tests/unit/organisations/test_unit_organisations_tasks.py @@ -312,6 +312,33 @@ def test_handle_api_usage_notification_for_organisation_when_billing_starts_at_i ] +def test_handle_api_usage_notification_for_organisation_when_cancellation_date_is_set( + organisation: Organisation, + inspecting_handler: logging.Handler, + mocker: MockerFixture, +) -> None: + # Given + organisation.subscription.plan = SCALE_UP + organisation.subscription.subscription_id = "fancy_id" + organisation.subscription.cancellation_date = timezone.now() + organisation.subscription.save() + mock_api_usage = mocker.patch("organisations.task_helpers.get_current_api_usage") + mock_api_usage.return_value = 25 + from organisations.task_helpers import logger + + logger.addHandler(inspecting_handler) + + # When + result = handle_api_usage_notification_for_organisation(organisation) + + # Then + assert result is None + assert OrganisationAPIUsageNotification.objects.count() == 0 + + # Check to ensure that error messages haven't been set. + assert inspecting_handler.messages == [] + + @pytest.mark.freeze_time("2023-01-19T09:09:47.325132+00:00") def test_handle_api_usage_notifications_when_feature_flag_is_off( mocker: MockerFixture, @@ -855,6 +882,50 @@ def test_charge_for_api_call_count_overages_scale_up( assert api_billing.billed_at == now +@pytest.mark.freeze_time("2023-01-19T09:09:47.325132+00:00") +def test_charge_for_api_call_count_overages_cancellation_date( + organisation: Organisation, + mocker: MockerFixture, +) -> None: + # Given + now = timezone.now() + OrganisationSubscriptionInformationCache.objects.create( + organisation=organisation, + allowed_seats=10, + allowed_projects=3, + allowed_30d_api_calls=100_000, + chargebee_email="test@example.com", + current_billing_term_starts_at=now - timedelta(days=30), + current_billing_term_ends_at=now + timedelta(minutes=30), + ) + organisation.subscription.subscription_id = "fancy_sub_id23" + organisation.subscription.plan = "scale-up-v2" + organisation.subscription.cancellation_date = timezone.now() + organisation.subscription.save() + OrganisationAPIUsageNotification.objects.create( + organisation=organisation, + percent_usage=100, + notified_at=now, + ) + + get_client_mock = mocker.patch("organisations.tasks.get_client") + client_mock = MagicMock() + get_client_mock.return_value = client_mock + + mock_api_usage = mocker.patch( + "organisations.tasks.get_current_api_usage", + ) + assert OrganisationAPIBilling.objects.count() == 0 + + # When + charge_for_api_call_count_overages() + + # Then + assert OrganisationAPIBilling.objects.count() == 0 + mock_api_usage.assert_not_called() + client_mock.get_identity_flags.assert_not_called() + + @pytest.mark.freeze_time("2023-01-19T09:09:47.325132+00:00") def test_charge_for_api_call_count_overages_scale_up_when_flagsmith_client_sets_is_enabled_to_false( organisation: Organisation,