diff --git a/api/organisations/chargebee/chargebee.py b/api/organisations/chargebee/chargebee.py index 02daa26cbbb1..cbcef7dc402a 100644 --- a/api/organisations/chargebee/chargebee.py +++ b/api/organisations/chargebee/chargebee.py @@ -31,7 +31,6 @@ from organisations.chargebee.constants import ( ADDITIONAL_API_SCALE_UP_ADDON_ID, ADDITIONAL_API_START_UP_ADDON_ID, - ADDITIONAL_SEAT_ADDON_ID, ) from organisations.chargebee.metadata import ChargebeeObjMetadata from organisations.subscriptions.constants import CHARGEBEE @@ -212,13 +211,11 @@ def add_single_seat(subscription_id: str) -> None: subscription = chargebee_client.Subscription.retrieve( subscription_id ).subscription + addon_id = _get_additional_seat_addon_id(subscription) + addons = subscription.addons or [] current_seats = next( - ( - addon.quantity - for addon in addons - if addon.id == ADDITIONAL_SEAT_ADDON_ID - ), + (addon.quantity for addon in addons if addon.id == addon_id), 0, ) @@ -227,7 +224,7 @@ def add_single_seat(subscription_id: str) -> None: SubscriptionOps.UpdateParams( addons=[ SubscriptionOps.UpdateAddonParams( - id=ADDITIONAL_SEAT_ADDON_ID, + id=_get_additional_seat_addon_id(subscription), quantity=current_seats + 1, ) ], @@ -254,6 +251,19 @@ def add_single_seat(subscription_id: str) -> None: raise UpgradeSeatsError(msg) from e +def _get_additional_seat_addon_id(subscription: SubscriptionOps) -> str: + addon_id_prefix = "additional-team-members-scale-up-v2" + addon_suffixes_by_billing_period = {1: "monthly", 6: "semiannual", 12: "annual"} + suffix = addon_suffixes_by_billing_period.get(subscription.billing_period) + if not suffix: + logger.warning( + "Unexpected billing period for subscription ID %s", + subscription.id, + ) + suffix = "monthly" + return "-".join([addon_id_prefix, suffix]) + + def add_100k_api_calls_start_up( subscription_id: str, count: int = 1, invoice_immediately: bool = False ) -> None: diff --git a/api/organisations/chargebee/constants.py b/api/organisations/chargebee/constants.py index af3135c0e926..c063d49586fc 100644 --- a/api/organisations/chargebee/constants.py +++ b/api/organisations/chargebee/constants.py @@ -1,4 +1,2 @@ -ADDITIONAL_SEAT_ADDON_ID = "additional-team-members-scale-up-v2" - ADDITIONAL_API_START_UP_ADDON_ID = "additional-api-start-up-monthly" ADDITIONAL_API_SCALE_UP_ADDON_ID = "additional-api-scale-up-monthly" diff --git a/api/tests/unit/organisations/chargebee/test_unit_chargebee_chargebee.py b/api/tests/unit/organisations/chargebee/test_unit_chargebee_chargebee.py index 5a2413a793e6..bf1ac00c5e16 100644 --- a/api/tests/unit/organisations/chargebee/test_unit_chargebee_chargebee.py +++ b/api/tests/unit/organisations/chargebee/test_unit_chargebee_chargebee.py @@ -35,7 +35,6 @@ ) from organisations.chargebee.constants import ( ADDITIONAL_API_SCALE_UP_ADDON_ID, - ADDITIONAL_SEAT_ADDON_ID, ) from organisations.chargebee.metadata import ChargebeeObjMetadata from organisations.subscriptions.exceptions import ( @@ -514,7 +513,7 @@ def test_get_subscription_metadata_from_id__addons_is_none__returns_plan_metadat def test_add_single_seat__existing_addon__increments_quantity(mocker) -> None: # type: ignore[no-untyped-def] # Given plan_id = "plan-id" - addon_id = ADDITIONAL_SEAT_ADDON_ID + addon_id = "additional-team-members-scale-up-v2-monthly" subscription_id = "subscription-id" addon_quantity = 1 @@ -523,6 +522,7 @@ def test_add_single_seat__existing_addon__increments_quantity(mocker) -> None: id=subscription_id, plan_id=plan_id, addons=[mocker.MagicMock(id=addon_id, quantity=addon_quantity)], + billing_period=1, ) mocked_chargebee = mocker.patch( "organisations.chargebee.chargebee.chargebee_client", autospec=True @@ -542,7 +542,7 @@ def test_add_single_seat__existing_addon__increments_quantity(mocker) -> None: SubscriptionOps.UpdateParams( addons=[ SubscriptionOps.UpdateAddonParams( - id=ADDITIONAL_SEAT_ADDON_ID, quantity=addon_quantity + 1 + id=addon_id, quantity=addon_quantity + 1 ) ], prorate=True, @@ -551,8 +551,19 @@ def test_add_single_seat__existing_addon__increments_quantity(mocker) -> None: ) -def test_add_single_seat__no_existing_addon__creates_addon_with_quantity_one( # type: ignore[no-untyped-def] - mocker, +@pytest.mark.parametrize( + "billing_period,expected_add_on_id", + ( + (1, "additional-team-members-scale-up-v2-monthly"), + (6, "additional-team-members-scale-up-v2-semiannual"), + (12, "additional-team-members-scale-up-v2-annual"), + # unexpected or missing billing period should default to monthly + (None, "additional-team-members-scale-up-v2-monthly"), + (7, "additional-team-members-scale-up-v2-monthly"), + ), +) +def test_add_single_seat__no_existing_addon__creates_addon_with_quantity_one( + mocker: MockerFixture, billing_period: int, expected_add_on_id: str ) -> None: # Given subscription_id = "subscription-id" @@ -562,6 +573,7 @@ def test_add_single_seat__no_existing_addon__creates_addon_with_quantity_one( # id=subscription_id, plan_id="plan_id", addons=[], + billing_period=billing_period, ) mocked_chargebee = mocker.patch( "organisations.chargebee.chargebee.chargebee_client", autospec=True @@ -580,9 +592,7 @@ def test_add_single_seat__no_existing_addon__creates_addon_with_quantity_one( # subscription_id, SubscriptionOps.UpdateParams( addons=[ - SubscriptionOps.UpdateAddonParams( - id=ADDITIONAL_SEAT_ADDON_ID, quantity=1 - ) + SubscriptionOps.UpdateAddonParams(id=expected_add_on_id, quantity=1) ], prorate=True, invoice_immediately=True, @@ -616,6 +626,7 @@ def test_add_single_seat__api_error__raises_upgrade_seats_error( # type: ignore id=subscription_id, plan_id="plan-id", addons=[], + billing_period=1, ) # tie that subscription object to the mocked chargebee object @@ -633,7 +644,7 @@ def test_add_single_seat__api_error__raises_upgrade_seats_error( # type: ignore SubscriptionOps.UpdateParams( addons=[ SubscriptionOps.UpdateAddonParams( - id=ADDITIONAL_SEAT_ADDON_ID, quantity=1 + id="additional-team-members-scale-up-v2-monthly", quantity=1 ) ], prorate=True,