remote-activity: Add column for rate paid on displayed plan.

Adds a column with the percentage rate that the remote server
or realm is paying on the displayed plan.

We display 0% for community plans that are 100% sponsored.
For legacy plans or plans with a scheduled downgrade, we
display a placeholder, "---". Otherwise, the value is
calculated from the CustomerPlan discount field.
This commit is contained in:
Lauryn Menard 2024-01-31 21:06:53 +01:00 committed by Tim Abbott
parent 649072977e
commit afe0161bc2
2 changed files with 74 additions and 47 deletions

View File

@ -28,7 +28,9 @@ from zerver.lib.utils import assert_is_not_none
from zerver.models import Realm from zerver.models import Realm
from zilencer.models import ( from zilencer.models import (
RemoteCustomerUserCount, RemoteCustomerUserCount,
RemoteRealm,
RemoteRealmAuditLog, RemoteRealmAuditLog,
RemoteZulipServer,
get_remote_customer_user_count, get_remote_customer_user_count,
) )
@ -45,6 +47,7 @@ class RemoteActivityPlanData:
current_status: str current_status: str
current_plan_name: str current_plan_name: str
annual_revenue: int annual_revenue: int
rate: str
def make_table( def make_table(
@ -159,6 +162,57 @@ def remote_installation_support_link(hostname: str) -> Markup:
return Markup('<a href="{url}"><i class="fa fa-gear"></i></a>').format(url=url) return Markup('<a href="{url}"><i class="fa fa-gear"></i></a>').format(url=url)
def get_plan_rate_percentage(discount: Optional[Decimal]) -> str:
if discount is None or discount == Decimal(0):
return "100%"
rate = 100 - discount
if rate * 100 % 100 == 0:
precision = 0
else:
precision = 2
return f"{rate:.{precision}f}%"
def get_remote_activity_plan_data(
plan: CustomerPlan,
license_ledger: LicenseLedger,
*,
remote_realm: Optional[RemoteRealm] = None,
remote_server: Optional[RemoteZulipServer] = None,
) -> RemoteActivityPlanData:
if plan.tier == CustomerPlan.TIER_SELF_HOSTED_LEGACY or plan.status in (
CustomerPlan.DOWNGRADE_AT_END_OF_FREE_TRIAL,
CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE,
):
renewal_cents = 0
current_rate = "---"
elif plan.tier == CustomerPlan.TIER_SELF_HOSTED_COMMUNITY:
renewal_cents = 0
current_rate = "0%"
elif remote_realm is not None:
renewal_cents = RemoteRealmBillingSession(
remote_realm=remote_realm
).get_customer_plan_renewal_amount(plan, license_ledger)
current_rate = get_plan_rate_percentage(plan.discount)
else:
assert remote_server is not None
renewal_cents = RemoteServerBillingSession(
remote_server=remote_server
).get_customer_plan_renewal_amount(plan, license_ledger)
current_rate = get_plan_rate_percentage(plan.discount)
if plan.billing_schedule == CustomerPlan.BILLING_SCHEDULE_MONTHLY:
renewal_cents *= 12
return RemoteActivityPlanData(
current_status=plan.get_plan_status_as_text(),
current_plan_name=plan.name,
annual_revenue=renewal_cents,
rate=current_rate,
)
def get_realms_with_default_discount_dict() -> Dict[str, Decimal]: def get_realms_with_default_discount_dict() -> Dict[str, Decimal]:
realms_with_default_discount: Dict[str, Any] = {} realms_with_default_discount: Dict[str, Any] = {}
customers = ( customers = (
@ -225,28 +279,17 @@ def get_plan_data_by_remote_server() -> Dict[int, RemoteActivityPlanData]: # no
) )
for plan in plans: for plan in plans:
renewal_cents = 0
server_id = None server_id = None
assert plan.customer.remote_server is not None assert plan.customer.remote_server is not None
server_id = plan.customer.remote_server.id server_id = plan.customer.remote_server.id
assert server_id is not None assert server_id is not None
latest_ledger_entry = plan.latest_ledger_entry[0] # type: ignore[attr-defined] # attribute from prefetch_related query latest_ledger_entry = plan.latest_ledger_entry[0] # type: ignore[attr-defined] # attribute from prefetch_related query
assert latest_ledger_entry is not None assert latest_ledger_entry is not None
if plan.tier in (
CustomerPlan.TIER_SELF_HOSTED_LEGACY, plan_data = get_remote_activity_plan_data(
CustomerPlan.TIER_SELF_HOSTED_COMMUNITY, plan, latest_ledger_entry, remote_server=plan.customer.remote_server
) or plan.status in ( )
CustomerPlan.DOWNGRADE_AT_END_OF_FREE_TRIAL,
CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE,
):
renewal_cents = 0
else:
renewal_cents = RemoteServerBillingSession(
remote_server=plan.customer.remote_server
).get_customer_plan_renewal_amount(plan, latest_ledger_entry)
if plan.billing_schedule == CustomerPlan.BILLING_SCHEDULE_MONTHLY:
renewal_cents *= 12
current_data = remote_server_plan_data.get(server_id) current_data = remote_server_plan_data.get(server_id)
if current_data is not None: if current_data is not None:
@ -256,15 +299,12 @@ def get_plan_data_by_remote_server() -> Dict[int, RemoteActivityPlanData]: # no
# a status that is less than the CustomerPlan.LIVE_STATUS_THRESHOLD. # a status that is less than the CustomerPlan.LIVE_STATUS_THRESHOLD.
remote_server_plan_data[server_id] = RemoteActivityPlanData( remote_server_plan_data[server_id] = RemoteActivityPlanData(
current_status="ERROR: MULTIPLE PLANS", current_status="ERROR: MULTIPLE PLANS",
current_plan_name=f"{current_plans}, {plan.name}", current_plan_name=f"{current_plans}, {plan_data.current_plan_name}",
annual_revenue=current_revenue + renewal_cents, annual_revenue=current_revenue + plan_data.annual_revenue,
rate="",
) )
else: else:
remote_server_plan_data[server_id] = RemoteActivityPlanData( remote_server_plan_data[server_id] = plan_data
current_status=plan.get_plan_status_as_text(),
current_plan_name=plan.name,
annual_revenue=renewal_cents,
)
return remote_server_plan_data return remote_server_plan_data
@ -289,33 +329,16 @@ def get_plan_data_by_remote_realm() -> Dict[int, Dict[int, RemoteActivityPlanDat
) )
for plan in plans: for plan in plans:
renewal_cents = 0
server_id = None server_id = None
assert plan.customer.remote_realm is not None assert plan.customer.remote_realm is not None
server_id = plan.customer.remote_realm.server_id server_id = plan.customer.remote_realm.server_id
assert server_id is not None assert server_id is not None
latest_ledger_entry = plan.latest_ledger_entry[0] # type: ignore[attr-defined] # attribute from prefetch_related query latest_ledger_entry = plan.latest_ledger_entry[0] # type: ignore[attr-defined] # attribute from prefetch_related query
assert latest_ledger_entry is not None assert latest_ledger_entry is not None
if plan.tier in (
CustomerPlan.TIER_SELF_HOSTED_LEGACY,
CustomerPlan.TIER_SELF_HOSTED_COMMUNITY,
) or plan.status in (
CustomerPlan.DOWNGRADE_AT_END_OF_FREE_TRIAL,
CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE,
):
renewal_cents = 0
else:
renewal_cents = RemoteRealmBillingSession(
remote_realm=plan.customer.remote_realm
).get_customer_plan_renewal_amount(plan, latest_ledger_entry)
if plan.billing_schedule == CustomerPlan.BILLING_SCHEDULE_MONTHLY:
renewal_cents *= 12
plan_data = RemoteActivityPlanData( plan_data = get_remote_activity_plan_data(
current_status=plan.get_plan_status_as_text(), plan, latest_ledger_entry, remote_realm=plan.customer.remote_realm
current_plan_name=plan.name,
annual_revenue=renewal_cents,
) )
current_server_data = remote_server_plan_data_by_realm.get(server_id) current_server_data = remote_server_plan_data_by_realm.get(server_id)
@ -334,8 +357,9 @@ def get_plan_data_by_remote_realm() -> Dict[int, Dict[int, RemoteActivityPlanDat
current_plans = current_realm_data.current_plan_name current_plans = current_realm_data.current_plan_name
current_server_data[realm_id] = RemoteActivityPlanData( current_server_data[realm_id] = RemoteActivityPlanData(
current_status="ERROR: MULTIPLE PLANS", current_status="ERROR: MULTIPLE PLANS",
current_plan_name=f"{current_plans}, {plan.name}", current_plan_name=f"{current_plans}, {plan_data.current_plan_name}",
annual_revenue=current_revenue + renewal_cents, annual_revenue=current_revenue + plan_data.annual_revenue,
rate="",
) )
else: else:
current_server_data[realm_id] = plan_data current_server_data[realm_id] = plan_data

View File

@ -91,6 +91,7 @@ def get_remote_server_activity(request: HttpRequest) -> HttpResponse:
"Plan name", "Plan name",
"Plan status", "Plan status",
"ARR", "ARR",
"Rate",
"Total users", "Total users",
"Guest users", "Guest users",
"Links", "Links",
@ -105,8 +106,8 @@ def get_remote_server_activity(request: HttpRequest) -> HttpResponse:
MOBILE_PUSH_COUNT = 7 MOBILE_PUSH_COUNT = 7
ORG_TYPE = 8 ORG_TYPE = 8
ARR = 11 ARR = 11
TOTAL_USER_COUNT = 12 TOTAL_USER_COUNT = 13
GUEST_COUNT = 13 GUEST_COUNT = 14
rows = get_query_data(query) rows = get_query_data(query)
plan_data_by_remote_server = get_plan_data_by_remote_server() plan_data_by_remote_server = get_plan_data_by_remote_server()
@ -171,12 +172,14 @@ def get_remote_server_activity(request: HttpRequest) -> HttpResponse:
row.append("---") row.append("---")
row.append("---") row.append("---")
row.append("---") row.append("---")
row.append("---")
else: else:
total_revenue += plan_data.annual_revenue total_revenue += plan_data.annual_revenue
revenue = cents_to_dollar_string(plan_data.annual_revenue) revenue = cents_to_dollar_string(plan_data.annual_revenue)
row.append(plan_data.current_plan_name) row.append(plan_data.current_plan_name)
row.append(plan_data.current_status) row.append(plan_data.current_status)
row.append(f"${revenue}") row.append(f"${revenue}")
row.append(plan_data.rate)
# Add user counts # Add user counts
if user_counts is None: if user_counts is None: