Upgrading to more than 10 seats on Team plan should suggest upgrading to Pro plan instead of throwing a generic error.
What product do you want to improve? Web application (Billing/upgrading module)
Is your feature request related to a problem? Please describe. When an org has 10 users on the Team plan and wants more seats, the error they get is generic and doesn't address the fact that the Team plan is limited to 10 users. This makes the checkout flow seem broken and confuses users. The error actually asks them to try again after refreshing their browser.
Describe the solution you'd like The error should say something like: "You've reached the max number of users for this plan, please upgrade to Pro." and link to them the Plans and Pricing page for reference.
Describe alternatives you've considered The current solution is that they write into support confused, or thinking something broken on their end and we tell them they need to upgrade to Pro instead.
Additional context Adding proper advice on how to upgrade will increase revenue by allowing orgs to upgrade on their first attempt, improve user experience, and lower the volume of support tickets related to billing issues.
ticket: https://sentry.zendesk.com/agent/tickets/150824
TLDR
The issue happened because plan_activated_users in https://github.com/codecov/shared/blob/main/shared/plan/service.py#L117 includes student users, while can_activate_user in https://github.com/codecov/shared/blob/main/shared/django_apps/codecov_auth/models.py#L194 excludes them. This mismatch caused the available plan logic to behave incorrectly.
To fix it, we should update plan_activated_users to mimic the can_activate_user logic, properly excluding student users when counting activated members.
This issue mentioned in the ticket is now resolved — here’s the full context for reference:
Initially, I fixed a runtime error by adding a ternary operator (so the page would stop erroring out). However, the logic was still incorrect — the page was showing the Pro plan instead of the Team plan. I continued investigating to find the root cause.
After a thorough investigation, I discovered that Team plans weren’t appearing in the list of available plans. That was the real problem.
While debugging, I noticed there were 11 activated users in the organization, even though the Team plan is supposed to have a maximum limit of 10 activated users. I deactivated member 4201676, and that immediately resolved the issue — the Team plan started appearing correctly.
Aftermath question: How was it even possible for a user to activate more than 10 users?
My hypothesis: There was no validation in place to prevent activating more than 10 users under the Team plan, which led to the logic breaking.
Here’s the relevant activation logic:
if "activated" in validated_data:
if validated_data["activated"] is True and owner.can_activate_user(instance):
owner.activate_user(instance)
def can_activate_user(self, owner_user: Self) -> bool:
owner_org = self
if owner_user.student:
return True
if owner_org.account:
return owner_org.account.can_activate_user(owner_user.user)
return owner_org.activated_user_count < owner_org.plan_user_count + owner_org.free
Data snapshot:
Plan activated user limit: 10
Plan free seats: 0
Plan user count: 10
However, in the dashboard, I saw 9 activated users out of 10 available seats.
Why the discrepancy? Because user 3881570 is associated with a student account. Student users don’t count towards the activation limit.
So technically, we had 9 active users < 10 seats, meaning activation was still allowed.
Tracing into the plans page: Specifically under the shared plans logic, here’s the relevant check when deciding whether to append the Team plan to available tiers:
if (
not self.plan_activated_users
or len(self.plan_activated_users) <= TEAM_PLAN_MAX_USERS
):
available_tiers.append(TierName.TEAM.value)
and
@property
def plan_activated_users(self) -> Optional[List[int]]:
"""Returns the list of activated users for the plan."""
return self.current_org.plan_activated_users
And that's where I discovered the real cause of the activated user discrepancy.