diff --git a/graphql_api/tests/test_plan.py b/graphql_api/tests/test_plan.py index 3daa441a04..38524f7f7e 100644 --- a/graphql_api/tests/test_plan.py +++ b/graphql_api/tests/test_plan.py @@ -77,3 +77,25 @@ def test_owner_plan_data_when_trialing(self): "pretrialUsersCount": 234, "planUserCount": 123, } + + def test_owner_plan_data_has_seats_left(self): + current_org = OwnerFactory( + username="random-plan-user", + service="github", + plan=PlanName.TRIAL_PLAN_NAME.value, + trial_status=TrialStatus.ONGOING.value, + plan_user_count=2, + plan_activated_users=[], + ) + query = """{ + owner(username: "%s") { + plan { + hasSeatsLeft + } + } + } + """ % ( + current_org.username + ) + data = self.gql_request(query, owner=current_org) + assert data["owner"]["plan"] == {"hasSeatsLeft": True} diff --git a/graphql_api/types/plan/plan.graphql b/graphql_api/types/plan/plan.graphql index 73548cd673..d73ce00f2e 100644 --- a/graphql_api/types/plan/plan.graphql +++ b/graphql_api/types/plan/plan.graphql @@ -16,4 +16,5 @@ type Plan { benefits: [String!]! monthlyUploadLimit: Int planUserCount: Int + hasSeatsLeft: Boolean! } diff --git a/graphql_api/types/plan/plan.py b/graphql_api/types/plan/plan.py index fed0c26ea5..c071896f18 100644 --- a/graphql_api/types/plan/plan.py +++ b/graphql_api/types/plan/plan.py @@ -95,3 +95,9 @@ def resolve_monthly_uploads_limit(plan_service: PlanService, info) -> Optional[i @convert_kwargs_to_snake_case def resolve_plan_user_count(plan_service: PlanService, info) -> int: return plan_service.plan_user_count + + +@plan_bindable.field("hasSeatsLeft") +@convert_kwargs_to_snake_case +def resolve_has_seats_left(plan_service: PlanService, info) -> bool: + return plan_service.has_seats_left diff --git a/plan/service.py b/plan/service.py index c63eb8bec4..f1692c33ea 100644 --- a/plan/service.py +++ b/plan/service.py @@ -258,3 +258,10 @@ def is_org_trialing(self) -> bool: @property def has_trial_dates(self) -> bool: return bool(self.trial_start_date and self.trial_end_date) + + @property + def has_seats_left(self) -> bool: + return ( + self.plan_activated_users is None + or len(self.plan_activated_users) < self.plan_user_count + ) diff --git a/plan/test_plan.py b/plan/test_plan.py index 4bef3d5d63..93db49aa80 100644 --- a/plan/test_plan.py +++ b/plan/test_plan.py @@ -317,6 +317,26 @@ def test_plan_service_returns_if_owner_has_trial_dates(self): assert plan_service.has_trial_dates == True + def test_plan_service_has_seats_left(self): + current_org = OwnerFactory( + plan=PlanName.TRIAL_PLAN_NAME.value, + plan_user_count=6, + plan_activated_users=[i for i in range(5)], + ) + plan_service = PlanService(current_org=current_org) + + assert plan_service.has_seats_left == True + + def test_plan_service_has_no_seats_left(self): + current_org = OwnerFactory( + plan=PlanName.TRIAL_PLAN_NAME.value, + plan_user_count=5, + plan_activated_users=[i for i in range(5)], + ) + plan_service = PlanService(current_org=current_org) + + assert plan_service.has_seats_left == False + class AvailablePlansBeforeTrial(TestCase): """