From e2853d7494b6fdab513e5ad5abf232585d97a078 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 1 Aug 2024 08:55:50 -0400 Subject: [PATCH] fix: Create a check for billing started at in API usage task helper (#4440) --- api/organisations/task_helpers.py | 8 +++++ .../test_unit_organisations_tasks.py | 36 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/api/organisations/task_helpers.py b/api/organisations/task_helpers.py index 96e99c671790..509811cbf622 100644 --- a/api/organisations/task_helpers.py +++ b/api/organisations/task_helpers.py @@ -106,6 +106,14 @@ def handle_api_usage_notification_for_organisation(organisation: Organisation) - subscription_cache = organisation.subscription_information_cache billing_starts_at = subscription_cache.current_billing_term_starts_at + if billing_starts_at is None: + # Since the calling code is a list of many organisations + # log the error and return without raising an exception. + logger.error( + f"Paid organisation {organisation.id} is missing billing_starts_at datetime" + ) + return + # Truncate to the closest active month to get start of current period. month_delta = relativedelta(now, billing_starts_at).months period_starts_at = relativedelta(months=month_delta) + billing_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 61dab9fb774d..6c853f097c41 100644 --- a/api/tests/unit/organisations/test_unit_organisations_tasks.py +++ b/api/tests/unit/organisations/test_unit_organisations_tasks.py @@ -33,6 +33,9 @@ SCALE_UP, ) from organisations.subscriptions.xero.metadata import XeroSubscriptionMetadata +from organisations.task_helpers import ( + handle_api_usage_notification_for_organisation, +) from organisations.tasks import ( ALERT_EMAIL_MESSAGE, ALERT_EMAIL_SUBJECT, @@ -244,6 +247,39 @@ def test_send_org_subscription_cancelled_alert(db: None, mocker: MockerFixture) ) +def test_handle_api_usage_notification_for_organisation_when_billing_starts_at_is_none( + organisation: Organisation, + inspecting_handler: logging.Handler, + mocker: MockerFixture, +) -> None: + # Given + api_usage_mock = mocker.patch("organisations.task_helpers.get_current_api_usage") + organisation.subscription.plan = SCALE_UP + organisation.subscription.subscription_id = "fancy_id" + organisation.subscription.save() + OrganisationSubscriptionInformationCache.objects.create( + organisation=organisation, + allowed_seats=10, + allowed_projects=3, + allowed_30d_api_calls=100, + chargebee_email="test@example.com", + current_billing_term_starts_at=None, + current_billing_term_ends_at=None, + ) + from organisations.task_helpers import logger + + logger.addHandler(inspecting_handler) + + # When + handle_api_usage_notification_for_organisation(organisation) + + # Then + api_usage_mock.assert_not_called() + assert inspecting_handler.messages == [ + f"Paid organisation {organisation.id} is missing billing_starts_at datetime" + ] + + @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,