mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 16:14:02 +00:00
stripe: Add get_sponsorship_request_context method to BillingSession.
This commit refactors 'sponsorship_request' view and adds 'BillingSession.get_sponsorship_request' method. This refactoring will help in minimizing duplicate code while supporting both realm and remote_Server customers.
This commit is contained in:
committed by
Tim Abbott
parent
1b17626327
commit
f8b0e16ff2
@@ -79,6 +79,11 @@ CARD_CAPITALIZATION = {
|
||||
"visa": "Visa",
|
||||
}
|
||||
|
||||
PAID_PLANS = [
|
||||
Realm.PLAN_TYPE_STANDARD,
|
||||
Realm.PLAN_TYPE_PLUS,
|
||||
]
|
||||
|
||||
# The version of Stripe API the billing system supports.
|
||||
STRIPE_API_VERSION = "2020-08-27"
|
||||
|
||||
@@ -207,6 +212,10 @@ def check_upgrade_parameters(
|
||||
)
|
||||
|
||||
|
||||
def is_realm_on_paid_plan(realm: Realm) -> bool:
|
||||
return realm.plan_type in PAID_PLANS
|
||||
|
||||
|
||||
# Be extremely careful changing this function. Historical billing periods
|
||||
# are not stored anywhere, and are just computed on the fly using this
|
||||
# function. Any change you make here should return the same value (or be
|
||||
@@ -634,6 +643,14 @@ class BillingSession(ABC):
|
||||
def has_billing_access(self) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def on_paid_plan(self) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_sponsorship_info_to_context(self, context: Dict[str, Any]) -> None:
|
||||
pass
|
||||
|
||||
@catch_stripe_errors
|
||||
def create_stripe_customer(self) -> Customer:
|
||||
stripe_customer_data = self.get_data_for_stripe_customer()
|
||||
@@ -1567,6 +1584,34 @@ class BillingSession(ABC):
|
||||
|
||||
raise JsonableError(_("Pass stripe_session_id or stripe_payment_intent_id"))
|
||||
|
||||
def get_sponsorship_request_context(self) -> Optional[Dict[str, Any]]:
|
||||
context: Dict[str, Any] = {}
|
||||
customer = self.get_customer()
|
||||
|
||||
if customer is not None and customer.sponsorship_pending:
|
||||
if self.on_paid_plan():
|
||||
return None
|
||||
|
||||
context["is_sponsorship_pending"] = True
|
||||
|
||||
if self.is_sponsored():
|
||||
context["is_sponsored"] = True
|
||||
|
||||
if customer is not None:
|
||||
plan = get_current_plan_by_customer(customer)
|
||||
if plan is not None:
|
||||
context["plan_name"] = plan.name
|
||||
context["free_trial"] = plan.is_free_trial()
|
||||
elif self.is_sponsored():
|
||||
# We don't create CustomerPlan objects for fully sponsored realms via support page.
|
||||
context["plan_name"] = "Zulip Cloud Standard"
|
||||
else:
|
||||
# TODO: Don't hardcode this plan name.
|
||||
context["plan_name"] = "Zulip Cloud Free"
|
||||
|
||||
self.add_sponsorship_info_to_context(context)
|
||||
return context
|
||||
|
||||
|
||||
class RealmBillingSession(BillingSession):
|
||||
def __init__(
|
||||
@@ -1814,6 +1859,27 @@ class RealmBillingSession(BillingSession):
|
||||
assert self.user is not None
|
||||
return self.user.has_billing_access
|
||||
|
||||
@override
|
||||
def on_paid_plan(self) -> bool:
|
||||
return is_realm_on_paid_plan(self.realm)
|
||||
|
||||
@override
|
||||
def add_sponsorship_info_to_context(self, context: Dict[str, Any]) -> None:
|
||||
def key_helper(d: Any) -> int:
|
||||
return d[1]["display_order"]
|
||||
|
||||
context.update(
|
||||
realm_org_type=self.realm.org_type,
|
||||
sorted_org_types=sorted(
|
||||
(
|
||||
[org_type_name, org_type]
|
||||
for (org_type_name, org_type) in Realm.ORG_TYPES.items()
|
||||
if not org_type.get("hidden")
|
||||
),
|
||||
key=key_helper,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class RemoteRealmBillingSession(BillingSession): # nocoverage
|
||||
def __init__(
|
||||
@@ -2015,6 +2081,16 @@ class RemoteRealmBillingSession(BillingSession): # nocoverage
|
||||
# session that isn't authorized for billing access.
|
||||
return True
|
||||
|
||||
@override
|
||||
def on_paid_plan(self) -> bool:
|
||||
# TBD
|
||||
return False
|
||||
|
||||
@override
|
||||
def add_sponsorship_info_to_context(self, context: Dict[str, Any]) -> None:
|
||||
# TBD
|
||||
pass
|
||||
|
||||
|
||||
class RemoteServerBillingSession(BillingSession): # nocoverage
|
||||
"""Billing session for pre-8.0 servers that do not yet support
|
||||
@@ -2211,6 +2287,16 @@ class RemoteServerBillingSession(BillingSession): # nocoverage
|
||||
# session that isn't authorized for billing access.
|
||||
return True
|
||||
|
||||
@override
|
||||
def on_paid_plan(self) -> bool:
|
||||
# TBD
|
||||
return False
|
||||
|
||||
@override
|
||||
def add_sponsorship_info_to_context(self, context: Dict[str, Any]) -> None:
|
||||
# TBD
|
||||
pass
|
||||
|
||||
|
||||
def stripe_customer_has_credit_card_as_default_payment_method(
|
||||
stripe_customer: stripe.Customer,
|
||||
|
@@ -5,72 +5,28 @@ from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse
|
||||
|
||||
from corporate.lib.stripe import RealmBillingSession, UpdatePlanRequest
|
||||
from corporate.models import CustomerPlan, get_current_plan_by_customer, get_customer_by_realm
|
||||
from corporate.lib.stripe import RealmBillingSession, UpdatePlanRequest, is_realm_on_paid_plan
|
||||
from corporate.models import CustomerPlan, get_customer_by_realm
|
||||
from zerver.decorator import require_billing_access, zulip_login_required
|
||||
from zerver.lib.request import REQ, has_request_variables
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.lib.validator import check_int, check_int_in, check_string
|
||||
from zerver.models import Realm, UserProfile
|
||||
from zerver.models import UserProfile
|
||||
|
||||
billing_logger = logging.getLogger("corporate.stripe")
|
||||
|
||||
PAID_PLANS = [
|
||||
Realm.PLAN_TYPE_STANDARD,
|
||||
Realm.PLAN_TYPE_PLUS,
|
||||
]
|
||||
|
||||
|
||||
def is_realm_on_paid_plan(realm: Realm) -> bool:
|
||||
return realm.plan_type in PAID_PLANS
|
||||
|
||||
|
||||
def add_sponsorship_info_to_context(context: Dict[str, Any], user_profile: UserProfile) -> None:
|
||||
def key_helper(d: Any) -> int:
|
||||
return d[1]["display_order"]
|
||||
|
||||
context.update(
|
||||
realm_org_type=user_profile.realm.org_type,
|
||||
sorted_org_types=sorted(
|
||||
(
|
||||
[org_type_name, org_type]
|
||||
for (org_type_name, org_type) in Realm.ORG_TYPES.items()
|
||||
if not org_type.get("hidden")
|
||||
),
|
||||
key=key_helper,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@zulip_login_required
|
||||
@has_request_variables
|
||||
def sponsorship_request(request: HttpRequest) -> HttpResponse:
|
||||
user = request.user
|
||||
assert user.is_authenticated
|
||||
context: Dict[str, Any] = {}
|
||||
|
||||
customer = get_customer_by_realm(user.realm)
|
||||
if customer is not None and customer.sponsorship_pending:
|
||||
if is_realm_on_paid_plan(user.realm):
|
||||
return HttpResponseRedirect(reverse("billing_home"))
|
||||
billing_session = RealmBillingSession(user)
|
||||
context = billing_session.get_sponsorship_request_context()
|
||||
if context is None:
|
||||
return HttpResponseRedirect(reverse("billing_home"))
|
||||
|
||||
context["is_sponsorship_pending"] = True
|
||||
|
||||
if user.realm.plan_type == user.realm.PLAN_TYPE_STANDARD_FREE:
|
||||
context["is_sponsored"] = True
|
||||
|
||||
if customer is not None:
|
||||
plan = get_current_plan_by_customer(customer)
|
||||
if plan is not None:
|
||||
context["plan_name"] = plan.name
|
||||
context["free_trial"] = plan.is_free_trial()
|
||||
# We don't create CustomerPlan objects for fully sponsored realms via support page.
|
||||
elif user.realm.plan_type == Realm.PLAN_TYPE_STANDARD_FREE:
|
||||
context["plan_name"] = "Zulip Cloud Standard"
|
||||
else:
|
||||
context["plan_name"] = "Zulip Cloud Free"
|
||||
|
||||
add_sponsorship_info_to_context(context, user)
|
||||
return render(request, "corporate/sponsorship.html", context=context)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user