mirror of
https://github.com/zulip/zulip.git
synced 2025-11-01 20:44:04 +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",
|
"visa": "Visa",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PAID_PLANS = [
|
||||||
|
Realm.PLAN_TYPE_STANDARD,
|
||||||
|
Realm.PLAN_TYPE_PLUS,
|
||||||
|
]
|
||||||
|
|
||||||
# The version of Stripe API the billing system supports.
|
# The version of Stripe API the billing system supports.
|
||||||
STRIPE_API_VERSION = "2020-08-27"
|
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
|
# Be extremely careful changing this function. Historical billing periods
|
||||||
# are not stored anywhere, and are just computed on the fly using this
|
# 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
|
# 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:
|
def has_billing_access(self) -> bool:
|
||||||
pass
|
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
|
@catch_stripe_errors
|
||||||
def create_stripe_customer(self) -> Customer:
|
def create_stripe_customer(self) -> Customer:
|
||||||
stripe_customer_data = self.get_data_for_stripe_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"))
|
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):
|
class RealmBillingSession(BillingSession):
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -1814,6 +1859,27 @@ class RealmBillingSession(BillingSession):
|
|||||||
assert self.user is not None
|
assert self.user is not None
|
||||||
return self.user.has_billing_access
|
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
|
class RemoteRealmBillingSession(BillingSession): # nocoverage
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -2015,6 +2081,16 @@ class RemoteRealmBillingSession(BillingSession): # nocoverage
|
|||||||
# session that isn't authorized for billing access.
|
# session that isn't authorized for billing access.
|
||||||
return True
|
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
|
class RemoteServerBillingSession(BillingSession): # nocoverage
|
||||||
"""Billing session for pre-8.0 servers that do not yet support
|
"""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.
|
# session that isn't authorized for billing access.
|
||||||
return True
|
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(
|
def stripe_customer_has_credit_card_as_default_payment_method(
|
||||||
stripe_customer: stripe.Customer,
|
stripe_customer: stripe.Customer,
|
||||||
|
|||||||
@@ -5,72 +5,28 @@ from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from corporate.lib.stripe import RealmBillingSession, UpdatePlanRequest
|
from corporate.lib.stripe import RealmBillingSession, UpdatePlanRequest, is_realm_on_paid_plan
|
||||||
from corporate.models import CustomerPlan, get_current_plan_by_customer, get_customer_by_realm
|
from corporate.models import CustomerPlan, get_customer_by_realm
|
||||||
from zerver.decorator import require_billing_access, zulip_login_required
|
from zerver.decorator import require_billing_access, zulip_login_required
|
||||||
from zerver.lib.request import REQ, has_request_variables
|
from zerver.lib.request import REQ, has_request_variables
|
||||||
from zerver.lib.response import json_success
|
from zerver.lib.response import json_success
|
||||||
from zerver.lib.validator import check_int, check_int_in, check_string
|
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")
|
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
|
@zulip_login_required
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def sponsorship_request(request: HttpRequest) -> HttpResponse:
|
def sponsorship_request(request: HttpRequest) -> HttpResponse:
|
||||||
user = request.user
|
user = request.user
|
||||||
assert user.is_authenticated
|
assert user.is_authenticated
|
||||||
context: Dict[str, Any] = {}
|
|
||||||
|
|
||||||
customer = get_customer_by_realm(user.realm)
|
billing_session = RealmBillingSession(user)
|
||||||
if customer is not None and customer.sponsorship_pending:
|
context = billing_session.get_sponsorship_request_context()
|
||||||
if is_realm_on_paid_plan(user.realm):
|
if context is None:
|
||||||
return HttpResponseRedirect(reverse("billing_home"))
|
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)
|
return render(request, "corporate/sponsorship.html", context=context)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user