stripe: Disable free trial for legacy customer with ended plan.

This ensures that customer who had legacy plan any time in the past
cannot avail free trial.
This commit is contained in:
Aman Agrawal 2024-02-22 04:30:41 +00:00 committed by Tim Abbott
parent b30f6bb705
commit bddb44eebf
50 changed files with 132 additions and 11 deletions

View File

@ -51,6 +51,7 @@ 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
@ -1847,10 +1848,11 @@ 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
remote_server_legacy_plan = self.get_remote_server_legacy_plan(customer)
if remote_server_legacy_plan is not None:
# Free trial is not available for legacy customers.
free_trial = False
should_schedule_upgrade_for_legacy_remote_server = (
remote_server_legacy_plan is not None
and upgrade_request.remote_server_plan_start_date == "billing_cycle_end_date"
@ -2420,6 +2422,9 @@ 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):
# Free trial is not available for legacy customers.
free_trial_days = None
if free_trial_days is not None:
_, _, free_trial_end, _ = compute_plan_parameters(
tier,

View File

@ -473,6 +473,12 @@ 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

@ -92,6 +92,7 @@ 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
@ -633,7 +634,18 @@ class StripeTestCase(ZulipTestCase):
return upgrade_json_response
is_self_hosted_billing = not isinstance(self.billing_session, RealmBillingSession)
if invoice or not talk_to_stripe or is_free_trial_offer_enabled(is_self_hosted_billing):
customer = self.billing_session.get_customer()
assert customer is not None
if (
invoice
or not talk_to_stripe
or (
is_free_trial_offer_enabled(is_self_hosted_billing)
and
# Free trial is not applicable for legacy customers.
not is_legacy_customer(customer)
)
):
# Upgrade already happened for free trial, invoice realms or schedule
# upgrade for legacy remote servers.
return upgrade_json_response
@ -7729,6 +7741,97 @@ class TestRemoteServerBillingFlow(StripeTestCase, RemoteServerTestCase):
f"INFO:corporate.stripe:Change plan status: Customer.id: {customer.id}, CustomerPlan.id: {customer_plan.id}, status: {CustomerPlan.ACTIVE}",
)
@responses.activate
@mock_stripe()
def test_free_trial_not_available_for_active_legacy_customer(self, *mocks: Mock) -> None:
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)
# Test that free trial is not available for customers with active legacy plan.
end_date = add_months(self.now, months=3)
self.billing_session.migrate_customer_to_legacy_plan(self.now, end_date)
result = self.execute_remote_billing_authentication_flow(
hamlet.delivery_email, hamlet.full_name
)
self.assertEqual(result.status_code, 302)
self.assertEqual(result["Location"], f"{self.billing_session.billing_base_url}/plans/")
with time_machine.travel(self.now, tick=False):
response = self.client_get(
f"{self.billing_session.billing_base_url}/plans/", subdomain="selfhosting"
)
self.assert_not_in_success_response(["free trial"], response)
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(["free trial"], response)
with time_machine.travel(self.now, tick=False):
self.add_card_and_upgrade(
tier=CustomerPlan.TIER_SELF_HOSTED_BASIC, schedule="monthly"
)
with time_machine.travel(self.now + timedelta(days=1), tick=False):
response = self.client_get(
f"{self.billing_session.billing_base_url}/billing/", subdomain="selfhosting"
)
self.assert_not_in_success_response(["(free trial)"], response)
@responses.activate
@mock_stripe()
def test_free_trial_not_available_for_ended_legacy_customer(self, *mocks: Mock) -> None:
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)
# Test that free trial is not available for customers with active legacy plan.
end_date = add_months(self.now, months=3)
self.billing_session.migrate_customer_to_legacy_plan(self.now, end_date)
CustomerPlan.objects.filter(customer__remote_server=self.remote_server).update(
status=CustomerPlan.ENDED
)
result = self.execute_remote_billing_authentication_flow(
hamlet.delivery_email, hamlet.full_name
)
self.assertEqual(result.status_code, 302)
self.assertEqual(result["Location"], f"{self.billing_session.billing_base_url}/plans/")
with time_machine.travel(self.now, tick=False):
response = self.client_get(
f"{self.billing_session.billing_base_url}/plans/", subdomain="selfhosting"
)
self.assert_not_in_success_response(["free trial"], response)
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(["free trial"], response)
with time_machine.travel(self.now, tick=False):
self.add_card_and_upgrade(
tier=CustomerPlan.TIER_SELF_HOSTED_BASIC, schedule="monthly"
)
with time_machine.travel(self.now + timedelta(days=1), tick=False):
response = self.client_get(
f"{self.billing_session.billing_base_url}/billing/", subdomain="selfhosting"
)
self.assert_not_in_success_response(["(free trial)"], response)
@responses.activate
@mock_stripe()
def test_upgrade_user_to_basic_plan_free_trial_remote_server(self, *mocks: Mock) -> None:

View File

@ -21,7 +21,12 @@ 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
from corporate.models import (
CustomerPlan,
get_current_plan_by_customer,
get_customer_by_realm,
is_legacy_customer,
)
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 (
@ -168,9 +173,6 @@ def remote_realm_plans_page(
if context.customer_plan is None:
context.on_free_tier = not context.is_sponsored
else:
if context.customer_plan.tier == CustomerPlan.TIER_SELF_HOSTED_LEGACY:
# Free trial is disabled for legacy customers.
context.free_trial_days = None
context.on_free_tier = (
context.customer_plan.tier
in (
@ -191,6 +193,10 @@ 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
context.is_new_customer = (
not context.on_free_tier and context.customer_plan is None and not context.is_sponsored
)
@ -234,9 +240,6 @@ def remote_server_plans_page(
if context.customer_plan is None:
context.on_free_tier = not context.is_sponsored
else:
if context.customer_plan.tier == CustomerPlan.TIER_SELF_HOSTED_LEGACY:
# Free trial is disabled for legacy customers.
context.free_trial_days = None
context.on_free_tier = context.customer_plan.tier in (
CustomerPlan.TIER_SELF_HOSTED_LEGACY,
CustomerPlan.TIER_SELF_HOSTED_BASE,
@ -253,6 +256,10 @@ def remote_server_plans_page(
status=CustomerPlan.NEVER_STARTED,
)
if is_legacy_customer(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
)