mirror of https://github.com/zulip/zulip.git
stripe: Add a CustomerPlan for self hosted sponsored customers.
This commit is contained in:
parent
d4a852e97c
commit
b2faa5c5bb
|
@ -2677,6 +2677,59 @@ class BillingSession(ABC):
|
|||
|
||||
self.do_change_plan_type(tier=CustomerPlan.TIER_SELF_HOSTED_LEGACY, is_sponsored=False)
|
||||
|
||||
def add_customer_to_community_plan(self) -> None:
|
||||
# There is no CustomerPlan for organizations on Zulip Cloud and
|
||||
# they enjoy the same benefits as the Standard plan.
|
||||
# For self-hosted organizations, sponsored organizations have
|
||||
# a Community CustomerPlan and they have different benefits compared
|
||||
# to customers on Business plan.
|
||||
assert not isinstance(self, RealmBillingSession)
|
||||
|
||||
customer = self.update_or_create_customer()
|
||||
plan = get_current_plan_by_customer(customer)
|
||||
# Only plan that can be active is legacy plan. Which is already
|
||||
# ended by the support path from which is this function is called.
|
||||
assert plan is None
|
||||
now = timezone_now()
|
||||
community_plan_params = {
|
||||
"billing_cycle_anchor": now,
|
||||
"status": CustomerPlan.ACTIVE,
|
||||
"tier": CustomerPlan.TIER_SELF_HOSTED_COMMUNITY,
|
||||
# The primary mechanism for preventing charges under this
|
||||
# plan is setting a null `next_invoice_date`, but setting
|
||||
# a 0 price is useful defense in depth here.
|
||||
"next_invoice_date": None,
|
||||
"price_per_license": 0,
|
||||
"billing_schedule": CustomerPlan.BILLING_SCHEDULE_ANNUAL,
|
||||
"automanage_licenses": True,
|
||||
}
|
||||
community_plan = CustomerPlan.objects.create(
|
||||
customer=customer,
|
||||
**community_plan_params,
|
||||
)
|
||||
|
||||
try:
|
||||
billed_licenses = self.get_billable_licenses_for_customer(customer, community_plan.tier)
|
||||
except MissingDataError:
|
||||
billed_licenses = 0
|
||||
|
||||
# Create a ledger entry for the community plan for tracking purposes.
|
||||
# Also, since it is an active plan we need to it have at least one license ledger entry.
|
||||
ledger_entry = LicenseLedger.objects.create(
|
||||
plan=community_plan,
|
||||
is_renewal=True,
|
||||
event_time=now,
|
||||
licenses=billed_licenses,
|
||||
licenses_at_next_renewal=billed_licenses,
|
||||
)
|
||||
community_plan.invoiced_through = ledger_entry
|
||||
community_plan.save(update_fields=["invoiced_through"])
|
||||
self.write_to_audit_log(
|
||||
event_type=AuditLogEventType.CUSTOMER_PLAN_CREATED,
|
||||
event_time=now,
|
||||
extra_data=community_plan_params,
|
||||
)
|
||||
|
||||
def get_last_ledger_for_automanaged_plan_if_exists(
|
||||
self,
|
||||
) -> Optional[LicenseLedger]: # nocoverage
|
||||
|
@ -2860,6 +2913,7 @@ class RealmBillingSession(BillingSession):
|
|||
# This function needs to translate between the different
|
||||
# formats of CustomerPlan.tier and Realm.plan_type.
|
||||
if is_sponsored:
|
||||
# Cloud sponsored customers don't have an active CustomerPlan.
|
||||
plan_type = Realm.PLAN_TYPE_STANDARD_FREE
|
||||
elif tier == CustomerPlan.TIER_CLOUD_STANDARD:
|
||||
plan_type = Realm.PLAN_TYPE_STANDARD
|
||||
|
@ -3199,11 +3253,13 @@ class RemoteRealmBillingSession(BillingSession):
|
|||
return customer
|
||||
|
||||
@override
|
||||
@transaction.atomic
|
||||
def do_change_plan_type(
|
||||
self, *, tier: Optional[int], is_sponsored: bool = False
|
||||
) -> None: # nocoverage
|
||||
if is_sponsored:
|
||||
plan_type = RemoteRealm.PLAN_TYPE_COMMUNITY
|
||||
self.add_customer_to_community_plan()
|
||||
elif tier == CustomerPlan.TIER_SELF_HOSTED_BUSINESS:
|
||||
plan_type = RemoteRealm.PLAN_TYPE_BUSINESS
|
||||
elif tier == CustomerPlan.TIER_SELF_HOSTED_LEGACY:
|
||||
|
@ -3581,6 +3637,7 @@ class RemoteServerBillingSession(BillingSession):
|
|||
return customer
|
||||
|
||||
@override
|
||||
@transaction.atomic
|
||||
def do_change_plan_type(
|
||||
self, *, tier: Optional[int], is_sponsored: bool = False
|
||||
) -> None: # nocoverage
|
||||
|
@ -3588,6 +3645,7 @@ class RemoteServerBillingSession(BillingSession):
|
|||
# formats of CustomerPlan.tier and RealmZulipServer.plan_type.
|
||||
if is_sponsored:
|
||||
plan_type = RemoteZulipServer.PLAN_TYPE_COMMUNITY
|
||||
self.add_customer_to_community_plan()
|
||||
elif tier == CustomerPlan.TIER_SELF_HOSTED_BUSINESS:
|
||||
plan_type = RemoteZulipServer.PLAN_TYPE_BUSINESS
|
||||
elif tier == CustomerPlan.TIER_SELF_HOSTED_LEGACY:
|
||||
|
|
|
@ -5797,6 +5797,14 @@ class TestRemoteRealmBillingFlow(StripeTestCase, RemoteRealmBillingTestCase):
|
|||
billing_session.approve_sponsorship()
|
||||
remote_realm.refresh_from_db()
|
||||
self.assertEqual(remote_realm.plan_type, RemoteRealm.PLAN_TYPE_COMMUNITY)
|
||||
# Assert such a plan exists
|
||||
CustomerPlan.objects.get(
|
||||
customer=customer,
|
||||
tier=CustomerPlan.TIER_SELF_HOSTED_COMMUNITY,
|
||||
status=CustomerPlan.ACTIVE,
|
||||
next_invoice_date=None,
|
||||
price_per_license=0,
|
||||
)
|
||||
|
||||
# Check email sent.
|
||||
expected_message = (
|
||||
|
@ -5920,6 +5928,14 @@ class TestRemoteServerBillingFlow(StripeTestCase, RemoteServerTestCase):
|
|||
billing_session.approve_sponsorship()
|
||||
self.remote_server.refresh_from_db()
|
||||
self.assertEqual(self.remote_server.plan_type, RemoteZulipServer.PLAN_TYPE_COMMUNITY)
|
||||
# Assert such a plan exists
|
||||
CustomerPlan.objects.get(
|
||||
customer=customer,
|
||||
tier=CustomerPlan.TIER_SELF_HOSTED_COMMUNITY,
|
||||
status=CustomerPlan.ACTIVE,
|
||||
next_invoice_date=None,
|
||||
price_per_license=0,
|
||||
)
|
||||
|
||||
# Check email sent.
|
||||
expected_message = (
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
{% endif %}
|
||||
<b>Plan name</b>: {{ plan_data.current_plan.name }}<br />
|
||||
<b>Status</b>: {{ plan_data.current_plan.get_plan_status_as_text() }}<br />
|
||||
{% if plan_data.current_plan.tier == plan_data.current_plan.TIER_SELF_HOSTED_COMMUNITY %}
|
||||
<!-- Any data below doesn't makes sense for sponsored organizations. -->
|
||||
{% else %}
|
||||
{% if plan_data.is_legacy_plan %}
|
||||
<b>End date</b>: {{ plan_data.current_plan.end_date.strftime('%d %B %Y') }}<br />
|
||||
{% else %}
|
||||
|
@ -19,3 +22,4 @@
|
|||
{% endif %}
|
||||
<b>Next invoice date</b>: {{ plan_data.current_plan.next_invoice_date.strftime('%d %B %Y') }}<br />
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in New Issue