diff --git a/api/organisations/tasks.py b/api/organisations/tasks.py index 0165360123f8..882927f2e2e6 100644 --- a/api/organisations/tasks.py +++ b/api/organisations/tasks.py @@ -253,6 +253,11 @@ def charge_for_api_call_count_overages(): subscription_cache = organisation.subscription_information_cache api_usage = get_current_api_usage(organisation.id, "30d") + # Grace period for organisations < 200% of usage. + if api_usage / subscription_cache.allowed_30d_api_calls < 2.0: + logger.info("API Usage below normal usage or grace period.") + continue + api_billings = OrganisationAPIBilling.objects.filter( billed_at__gte=subscription_cache.current_billing_term_starts_at ) diff --git a/api/tests/unit/organisations/test_unit_organisations_tasks.py b/api/tests/unit/organisations/test_unit_organisations_tasks.py index dd8699f158a5..cf6444216e94 100644 --- a/api/tests/unit/organisations/test_unit_organisations_tasks.py +++ b/api/tests/unit/organisations/test_unit_organisations_tasks.py @@ -527,6 +527,49 @@ 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_grace_period( + 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.save() + OrganisationAPIUsageNotification.objects.create( + organisation=organisation, + percent_usage=100, + notified_at=now, + ) + + mock_chargebee_update = mocker.patch( + "organisations.chargebee.chargebee.chargebee.Subscription.update" + ) + mock_api_usage = mocker.patch( + "organisations.tasks.get_current_api_usage", + ) + # Set the return value to something less than 200% of base rate + mock_api_usage.return_value = 115_000 + assert OrganisationAPIBilling.objects.count() == 0 + + # When + charge_for_api_call_count_overages() + + # Then + mock_chargebee_update.assert_not_called() + assert OrganisationAPIBilling.objects.count() == 0 + + @pytest.mark.freeze_time("2023-01-19T09:09:47.325132+00:00") def test_charge_for_api_call_count_overages_with_not_covered_plan( organisation: Organisation,