2023-12-02 17:55:39 +01:00
|
|
|
from dataclasses import dataclass
|
2023-10-31 19:22:55 +01:00
|
|
|
from decimal import Decimal
|
|
|
|
from typing import Optional
|
2021-09-29 19:51:55 +02:00
|
|
|
from urllib.parse import urlencode, urljoin, urlunsplit
|
|
|
|
|
|
|
|
from django.conf import settings
|
|
|
|
from django.urls import reverse
|
2023-12-02 17:55:39 +01:00
|
|
|
from django.utils.timezone import now as timezone_now
|
2021-09-29 19:51:55 +02:00
|
|
|
|
2023-12-02 17:55:39 +01:00
|
|
|
from corporate.lib.stripe import BillingSession
|
|
|
|
from corporate.models import Customer, CustomerPlan, get_current_plan_by_customer
|
2023-12-01 12:23:31 +01:00
|
|
|
from zerver.models import Realm, get_realm
|
2023-12-06 18:16:20 +01:00
|
|
|
from zilencer.lib.remote_counts import MissingDataError
|
2021-09-29 19:51:55 +02:00
|
|
|
|
|
|
|
|
2023-12-02 17:55:39 +01:00
|
|
|
@dataclass
|
|
|
|
class PlanData:
|
|
|
|
customer: Optional["Customer"] = None
|
|
|
|
current_plan: Optional["CustomerPlan"] = None
|
|
|
|
licenses: Optional[int] = None
|
|
|
|
licenses_used: Optional[int] = None
|
2023-12-06 18:09:34 +01:00
|
|
|
is_legacy_plan: bool = False
|
2023-12-06 18:16:20 +01:00
|
|
|
warning: Optional[str] = None
|
2023-12-02 17:55:39 +01:00
|
|
|
|
|
|
|
|
2023-12-06 15:00:23 +01:00
|
|
|
def get_realm_support_url(realm: Realm) -> str:
|
2021-09-29 19:51:55 +02:00
|
|
|
support_realm_uri = get_realm(settings.STAFF_SUBDOMAIN).uri
|
|
|
|
support_url = urljoin(
|
|
|
|
support_realm_uri,
|
|
|
|
urlunsplit(("", "", reverse("support"), urlencode({"q": realm.string_id}), "")),
|
|
|
|
)
|
|
|
|
return support_url
|
2023-10-31 19:22:55 +01:00
|
|
|
|
|
|
|
|
2023-12-02 17:45:25 +01:00
|
|
|
def get_customer_discount_for_support_view(
|
|
|
|
customer: Optional[Customer] = None,
|
|
|
|
) -> Optional[Decimal]:
|
|
|
|
if customer is None:
|
|
|
|
return None
|
|
|
|
return customer.default_discount
|
2023-12-02 17:55:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
def get_current_plan_data_for_support_view(billing_session: BillingSession) -> PlanData:
|
|
|
|
customer = billing_session.get_customer()
|
|
|
|
plan = None
|
|
|
|
if customer is not None:
|
|
|
|
plan = get_current_plan_by_customer(customer)
|
|
|
|
plan_data = PlanData(
|
|
|
|
customer=customer,
|
|
|
|
current_plan=plan,
|
|
|
|
)
|
|
|
|
if plan is not None:
|
|
|
|
new_plan, last_ledger_entry = billing_session.make_end_of_cycle_updates_if_needed(
|
|
|
|
plan, timezone_now()
|
|
|
|
)
|
|
|
|
if last_ledger_entry is not None:
|
|
|
|
if new_plan is not None:
|
|
|
|
plan_data.current_plan = new_plan # nocoverage
|
|
|
|
plan_data.licenses = last_ledger_entry.licenses
|
2023-12-06 18:16:20 +01:00
|
|
|
try:
|
|
|
|
plan_data.licenses_used = billing_session.current_count_for_billed_licenses()
|
|
|
|
except MissingDataError: # nocoverage
|
|
|
|
plan_data.warning = "Recent data missing: No information for used licenses"
|
2023-12-06 18:09:34 +01:00
|
|
|
assert plan_data.current_plan is not None # for mypy
|
|
|
|
plan_data.is_legacy_plan = (
|
|
|
|
plan_data.current_plan.tier == CustomerPlan.TIER_SELF_HOSTED_LEGACY
|
|
|
|
)
|
2023-12-02 17:55:39 +01:00
|
|
|
|
|
|
|
return plan_data
|