From c4b6cfe142f2b04bf69586d1c1dc7fed5c001042 Mon Sep 17 00:00:00 2001 From: Prakhar Pratyush Date: Wed, 31 Jan 2024 18:40:45 +0530 Subject: [PATCH] support: Fix next plan info missing for customers with no current plan. Earlier, when a fixed-price plan for a customer with no current plan was configured via /support, the next plan info was missing on support page. It was because we were considering next plan only if the customer had a current plan. This commit fixes the incorrect behaviour. --- corporate/lib/stripe.py | 17 +++-------------- corporate/lib/support.py | 13 ++++++++++++- corporate/tests/test_stripe.py | 9 ++++++--- corporate/tests/test_support_views.py | 1 - 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/corporate/lib/stripe.py b/corporate/lib/stripe.py index 3870450d5c..9fef1dab81 100644 --- a/corporate/lib/stripe.py +++ b/corporate/lib/stripe.py @@ -1958,23 +1958,14 @@ class BillingSession(ABC): return None, None return None, last_ledger_entry - def get_next_plan(self, plan: CustomerPlan) -> Union[CustomerPlan, CustomerPlanOffer, None]: - customer = plan.customer + def get_next_plan(self, plan: CustomerPlan) -> Optional[CustomerPlan]: if plan.status == CustomerPlan.SWITCH_PLAN_TIER_AT_PLAN_END: assert plan.end_date is not None return CustomerPlan.objects.filter( - customer=customer, + customer=plan.customer, billing_cycle_anchor=plan.end_date, status=CustomerPlan.NEVER_STARTED, ).first() - elif customer.required_plan_tier is not None: - # Currently, the only case when a next_plan is scheduled with the - # current_plan.status NOT SET to SWITCH_PLAN_TIER_AT_PLAN_END is a - # fixed price plan configured via /support which the customer is yet - # to buy or schedule a purchase. - return get_configured_fixed_price_plan_offer( - customer=customer, plan_tier=customer.required_plan_tier - ) return None def get_customer_plan_renewal_amount( @@ -2136,7 +2127,6 @@ class BillingSession(ABC): next_plan = self.get_next_plan(plan) if next_plan is not None: - assert type(next_plan) is CustomerPlan next_plan_context = self.get_billing_context_from_plan( customer, next_plan, last_ledger_entry, now ) @@ -2394,9 +2384,8 @@ class BillingSession(ABC): # Switch to a different plan was cancelled. We end the next plan # and set the current one as active. if plan.status == CustomerPlan.SWITCH_PLAN_TIER_AT_PLAN_END: - assert type(plan) is CustomerPlan next_plan = self.get_next_plan(plan) - assert type(next_plan) is CustomerPlan + assert next_plan is not None do_change_plan_status(next_plan, CustomerPlan.ENDED) do_change_plan_status(plan, status) elif status == CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE: diff --git a/corporate/lib/support.py b/corporate/lib/support.py index e56c8fa902..ae167a2dfa 100644 --- a/corporate/lib/support.py +++ b/corporate/lib/support.py @@ -13,6 +13,7 @@ from corporate.lib.stripe import ( BillingSession, RemoteRealmBillingSession, RemoteServerBillingSession, + get_configured_fixed_price_plan_offer, start_of_next_billing_cycle, ) from corporate.models import ( @@ -156,6 +157,15 @@ def get_current_plan_data_for_support_view(billing_session: BillingSession) -> P customer=customer, current_plan=plan, ) + + # A customer with or without a current plan can have a fixed_price next plan configured. + if customer and customer.required_plan_tier: + plan_data.next_plan = get_configured_fixed_price_plan_offer( + customer, customer.required_plan_tier + ) + if plan_data.next_plan: + plan_data.estimated_next_plan_revenue = plan_data.next_plan.fixed_price + if plan is not None: new_plan, last_ledger_entry = billing_session.make_end_of_cycle_updates_if_needed( plan, timezone_now() @@ -172,7 +182,8 @@ def get_current_plan_data_for_support_view(billing_session: BillingSession) -> P ) assert plan_data.current_plan is not None # for mypy - plan_data.next_plan = billing_session.get_next_plan(plan_data.current_plan) + if plan_data.next_plan is None: + plan_data.next_plan = billing_session.get_next_plan(plan_data.current_plan) if plan_data.next_plan is not None: if plan_data.next_plan.fixed_price is not None: # nocoverage diff --git a/corporate/tests/test_stripe.py b/corporate/tests/test_stripe.py index c327fde962..df0469b692 100644 --- a/corporate/tests/test_stripe.py +++ b/corporate/tests/test_stripe.py @@ -6223,6 +6223,12 @@ class TestRemoteRealmBillingFlow(StripeTestCase, RemoteRealmBillingTestCase): self.assertEqual(fixed_price_plan_offer.fixed_price, annual_fixed_price * 100) self.assertEqual(fixed_price_plan_offer.get_plan_status_as_text(), "Configured") + result = self.client_get("/activity/remote/support", {"q": "example.com"}) + self.assert_in_success_response( + ["Next plan information:", "Zulip Basic", "Configured", "Plan has a fixed price."], + result, + ) + self.logout() self.login("hamlet") hamlet = self.example_user("hamlet") @@ -6886,7 +6892,6 @@ class TestRemoteRealmBillingFlow(StripeTestCase, RemoteRealmBillingTestCase): new_plan = self.billing_session.get_next_plan(realm_legacy_plan) assert new_plan is not None - assert type(new_plan) is CustomerPlan self.assertEqual(new_plan.tier, CustomerPlan.TIER_SELF_HOSTED_BUSINESS) self.assertEqual(new_plan.status, CustomerPlan.NEVER_STARTED) self.assertEqual( @@ -7247,7 +7252,6 @@ class TestRemoteServerBillingFlow(StripeTestCase, RemoteServerTestCase): self.assertEqual(customer_plan.end_date, end_date) new_customer_plan = self.billing_session.get_next_plan(customer_plan) assert new_customer_plan is not None - assert type(new_customer_plan) is CustomerPlan self.assertEqual(new_customer_plan.tier, CustomerPlan.TIER_SELF_HOSTED_BUSINESS) self.assertEqual(new_customer_plan.status, CustomerPlan.NEVER_STARTED) self.assertEqual(new_customer_plan.billing_cycle_anchor, end_date) @@ -8082,7 +8086,6 @@ class TestRemoteServerBillingFlow(StripeTestCase, RemoteServerTestCase): self.assertEqual(legacy_plan.status, CustomerPlan.SWITCH_PLAN_TIER_AT_PLAN_END) new_plan = self.billing_session.get_next_plan(legacy_plan) assert new_plan is not None - assert type(new_plan) is CustomerPlan self.assertEqual(new_plan.tier, CustomerPlan.TIER_SELF_HOSTED_BUSINESS) self.assertEqual(new_plan.status, CustomerPlan.NEVER_STARTED) self.assertEqual( diff --git a/corporate/tests/test_support_views.py b/corporate/tests/test_support_views.py index 53067b079b..e5df0abff0 100644 --- a/corporate/tests/test_support_views.py +++ b/corporate/tests/test_support_views.py @@ -404,7 +404,6 @@ class TestRemoteServerSupportEndpoint(ZulipTestCase): assert plan is not None next_plan = billing_session.get_next_plan(plan) assert next_plan is not None - assert type(next_plan) is CustomerPlan self.assertEqual(plan.status, CustomerPlan.SWITCH_PLAN_TIER_AT_PLAN_END) self.assertEqual(next_plan.status, CustomerPlan.NEVER_STARTED)