upgrade: Fix allowed free trails for ended legacy plans on server.

If the remote realm registered after the legacy plan on server
ENDED, we never migrate the plan to the remote realm. So, we need
to check the server of remote realm whenever we are check remote
realm for legacy plan.
This commit is contained in:
Aman Agrawal
2024-03-15 02:03:11 +00:00
committed by Tim Abbott
parent ef5cdff9d9
commit e10f81197f
4 changed files with 114 additions and 23 deletions

View File

@@ -51,7 +51,6 @@ from corporate.models import (
get_customer_by_realm,
get_customer_by_remote_realm,
get_customer_by_remote_server,
is_legacy_customer,
)
from zerver.lib.exceptions import JsonableError
from zerver.lib.logging_util import log_to_file
@@ -761,6 +760,32 @@ class BillingSession(ABC):
def org_name(self) -> str:
pass
def is_legacy_customer(self) -> bool:
if isinstance(self, RealmBillingSession):
return False
customers_to_check = []
if isinstance(self, RemoteRealmBillingSession):
customer = self.get_customer()
if customer is not None:
customers_to_check.append(customer)
# Also, check if server for a remote realm was ever on a legacy plan.
# We don't migrate ENDED legacy plans from server to remote realm, so we can end
# in this state if the first time they registered with us was after the legacy plan.
server_customer = get_customer_by_remote_server(self.remote_realm.server)
if server_customer is not None:
customers_to_check.append(server_customer)
if isinstance(self, RemoteServerBillingSession):
customer = self.get_customer()
if customer is not None:
customers_to_check.append(customer)
return CustomerPlan.objects.filter(
customer__in=customers_to_check, tier=CustomerPlan.TIER_SELF_HOSTED_LEGACY
).exists()
def get_past_invoices_session_url(self) -> str:
headline = "List of past invoices"
customer = self.get_customer()
@@ -1860,9 +1885,9 @@ class BillingSession(ABC):
if fixed_price_plan_offer is not None:
free_trial = False
if is_legacy_customer(customer):
# Free trial is not available for legacy customers.
free_trial = False
if self.is_legacy_customer():
# Free trial is not available for legacy customers.
free_trial = False
remote_server_legacy_plan = self.get_remote_server_legacy_plan(customer)
should_schedule_upgrade_for_legacy_remote_server = (
@@ -2454,7 +2479,7 @@ class BillingSession(ABC):
is_self_hosted_billing = not isinstance(self, RealmBillingSession)
if fixed_price is None and remote_server_legacy_plan_end_date is None:
free_trial_days = get_free_trial_days(is_self_hosted_billing, tier)
if customer is not None and is_legacy_customer(customer):
if self.is_legacy_customer():
# Free trial is not available for legacy customers.
free_trial_days = None
if free_trial_days is not None:

View File

@@ -484,12 +484,6 @@ def get_current_plan_by_customer(customer: Customer) -> Optional[CustomerPlan]:
).first()
def is_legacy_customer(customer: Customer) -> bool:
return CustomerPlan.objects.filter(
customer=customer, tier=CustomerPlan.TIER_SELF_HOSTED_LEGACY
).exists()
def get_current_plan_by_realm(realm: Realm) -> Optional[CustomerPlan]:
customer = get_customer_by_realm(realm)
if customer is None:

View File

@@ -91,7 +91,6 @@ from corporate.models import (
get_current_plan_by_realm,
get_customer_by_realm,
get_customer_by_remote_realm,
is_legacy_customer,
)
from corporate.tests.test_remote_billing import RemoteRealmBillingTestCase, RemoteServerTestCase
from corporate.views.remote_billing_page import generate_confirmation_link_for_server_deactivation
@@ -640,7 +639,7 @@ class StripeTestCase(ZulipTestCase):
is_free_trial_offer_enabled(is_self_hosted_billing)
and
# Free trial is not applicable for legacy customers.
not is_legacy_customer(customer)
not self.billing_session.is_legacy_customer()
):
# Upgrade already happened for free trial, invoice realms or schedule
# upgrade for legacy remote servers.
@@ -6087,6 +6086,84 @@ class TestRemoteRealmBillingFlow(StripeTestCase, RemoteRealmBillingTestCase):
self.assertEqual(response.status_code, 302)
self.assertTrue(response["Location"].startswith("https://billing.stripe.com"))
@responses.activate
@mock_stripe()
def test_upgrade_user_to_basic_plan_free_trial_fails_special_case(self, *mocks: Mock) -> None:
# Here we test if server had a legacy plan but never it ended before we could ever migrate
# it to remote realm resulting in the upgrade for remote realm creating a new customer which
# doesn't have any legacy plan associated with it. In this case, free trail should not be offered.
with self.settings(SELF_HOSTING_FREE_TRIAL_DAYS=30):
self.login("hamlet")
hamlet = self.example_user("hamlet")
self.add_mock_response()
with time_machine.travel(self.now, tick=False):
send_server_data_to_push_bouncer(consider_usage_statistics=False)
result = self.execute_remote_billing_authentication_flow(hamlet)
self.assertEqual(result.status_code, 302)
self.assertEqual(result["Location"], f"{self.billing_session.billing_base_url}/plans/")
# Test under normal circumstances it will show free trial.
with time_machine.travel(self.now, tick=False):
result = self.client_get(
f"{self.billing_session.billing_base_url}/upgrade/?tier={CustomerPlan.TIER_SELF_HOSTED_BASIC}",
subdomain="selfhosting",
)
self.assert_in_success_response(
[
"Start free trial",
"Zulip Basic",
"Start 30-day free trial",
],
result,
)
# Add ended legacy plan for remote realm server.
new_server_customer = Customer.objects.create(remote_server=self.remote_realm.server)
CustomerPlan.objects.create(
customer=new_server_customer,
status=CustomerPlan.ENDED,
tier=CustomerPlan.TIER_SELF_HOSTED_LEGACY,
billing_cycle_anchor=timezone_now(),
billing_schedule=CustomerPlan.BILLING_SCHEDULE_ANNUAL,
)
# No longer eligible for free trial
with time_machine.travel(self.now, tick=False):
result = self.client_get(
f"{self.billing_session.billing_base_url}/upgrade/?tier={CustomerPlan.TIER_SELF_HOSTED_BASIC}",
subdomain="selfhosting",
)
self.assert_not_in_success_response(
[
"Start free trial",
"Start 30-day free trial",
],
result,
)
self.assert_in_success_response(
[
"Purchase Zulip Basic",
],
result,
)
result = self.client_get(
f"{self.billing_session.billing_base_url}/plans/",
subdomain="selfhosting",
)
self.assert_not_in_success_response(
[
"Start 30-day free trial",
],
result,
)
@responses.activate
@mock_stripe()
def test_upgrade_user_to_basic_plan_free_trial(self, *mocks: Mock) -> None:

View File

@@ -21,12 +21,7 @@ from corporate.lib.stripe import (
get_configured_fixed_price_plan_offer,
get_free_trial_days,
)
from corporate.models import (
CustomerPlan,
get_current_plan_by_customer,
get_customer_by_realm,
is_legacy_customer,
)
from corporate.models import CustomerPlan, get_current_plan_by_customer, get_customer_by_realm
from zerver.context_processors import get_realm_from_request, latest_info_context
from zerver.decorator import add_google_analytics, zulip_login_required
from zerver.lib.github import (
@@ -193,9 +188,9 @@ def remote_realm_plans_page(
status=CustomerPlan.NEVER_STARTED,
)
if is_legacy_customer(customer):
# Free trial is disabled for legacy customers.
context.free_trial_days = None
if billing_session.is_legacy_customer():
# Free trial is disabled for legacy customers.
context.free_trial_days = None
context.is_new_customer = (
not context.on_free_tier and context.customer_plan is None and not context.is_sponsored
@@ -256,7 +251,7 @@ def remote_server_plans_page(
status=CustomerPlan.NEVER_STARTED,
)
if is_legacy_customer(customer):
if billing_session.is_legacy_customer():
# Free trial is disabled for legacy customers.
context.free_trial_days = None