corporate: Check for no CustomerPlan on Customer instead of Realm.

In ensure_customer_does_not_have_active_plan, we were already going
through the Customer table to get/check for an active CustomerPlan.

Now we directly get/check for an active CustomerPlan with via the
Customer, which allows for reusing this function for Customer
objects without a Realm set.
This commit is contained in:
Lauryn Menard 2023-10-30 22:29:22 +01:00 committed by Tim Abbott
parent 85ab5b70e9
commit d1e2e2d857
4 changed files with 15 additions and 14 deletions

View File

@ -628,14 +628,14 @@ def is_free_trial_offer_enabled() -> bool:
return settings.FREE_TRIAL_DAYS not in (None, 0)
def ensure_realm_does_not_have_active_plan(realm: Realm) -> None:
if get_current_plan_by_realm(realm) is not None:
def ensure_customer_does_not_have_active_plan(customer: Customer) -> None:
if get_current_plan_by_customer(customer) is not None:
# Unlikely race condition from two people upgrading (clicking "Make payment")
# at exactly the same time. Doesn't fully resolve the race condition, but having
# a check here reduces the likelihood.
billing_logger.warning(
"Upgrade of %s failed because of existing active plan.",
realm.string_id,
str(customer),
)
raise UpgradeWithExistingPlanError
@ -685,7 +685,7 @@ def process_initial_upgrade(
customer = update_or_create_stripe_customer(user)
assert customer.stripe_customer_id is not None # for mypy
assert customer.realm is not None
ensure_realm_does_not_have_active_plan(customer.realm)
ensure_customer_does_not_have_active_plan(customer)
(
billing_cycle_anchor,
next_invoice_date,

View File

@ -8,7 +8,7 @@ from django.conf import settings
from corporate.lib.stripe import (
BillingError,
UpgradeWithExistingPlanError,
ensure_realm_does_not_have_active_plan,
ensure_customer_does_not_have_active_plan,
process_initial_upgrade,
update_or_create_stripe_customer,
)
@ -81,7 +81,7 @@ def handle_checkout_session_completed_event(
Session.UPGRADE_FROM_BILLING_PAGE,
Session.RETRY_UPGRADE_WITH_ANOTHER_PAYMENT_METHOD,
]:
ensure_realm_does_not_have_active_plan(user.realm)
ensure_customer_does_not_have_active_plan(session.customer)
update_or_create_stripe_customer(user, payment_method)
assert session.payment_intent is not None
session.payment_intent.status = PaymentIntent.PROCESSING
@ -97,7 +97,7 @@ def handle_checkout_session_completed_event(
Session.FREE_TRIAL_UPGRADE_FROM_BILLING_PAGE,
Session.FREE_TRIAL_UPGRADE_FROM_ONBOARDING_PAGE,
]:
ensure_realm_does_not_have_active_plan(user.realm)
ensure_customer_does_not_have_active_plan(session.customer)
update_or_create_stripe_customer(user, payment_method)
process_initial_upgrade(
user,
@ -136,7 +136,7 @@ def handle_payment_intent_succeeded_event(
discountable=False,
)
try:
ensure_realm_does_not_have_active_plan(user.realm)
ensure_customer_does_not_have_active_plan(payment_intent.customer)
except UpgradeWithExistingPlanError as e:
stripe_invoice = stripe.Invoice.create(
auto_advance=True,

View File

@ -624,7 +624,7 @@ class StripeTestCase(ZulipTestCase):
class StripeMock(Mock):
def __init__(self, depth: int = 1) -> None:
super().__init__(spec=stripe.Card)
self.id = "id"
self.id = "cus_123"
self.created = "1000"
self.last4 = "4242"
@ -1894,7 +1894,7 @@ class StripeTest(StripeTestCase):
)
self.assertEqual(
m.output[0],
"WARNING:corporate.stripe:Upgrade of zulip failed because of existing active plan.",
"WARNING:corporate.stripe:Upgrade of <Realm: zulip 2> (with stripe_customer_id: cus_123) failed because of existing active plan.",
)
self.assert_length(m.output, 1)
@ -3247,7 +3247,7 @@ class StripeTest(StripeTestCase):
self.local_upgrade(self.seat_count, True, CustomerPlan.ANNUAL, True, False)
self.assertEqual(
m.output[0],
"WARNING:corporate.stripe:Upgrade of zulip failed because of existing active plan.",
"WARNING:corporate.stripe:Upgrade of <Realm: zulip 2> (with stripe_customer_id: cus_123) failed because of existing active plan.",
)
self.assertEqual(
context.exception.error_description, "subscribing with existing subscription"

View File

@ -16,7 +16,7 @@ from corporate.lib.stripe import (
MIN_INVOICED_LICENSES,
BillingError,
compute_plan_parameters,
ensure_realm_does_not_have_active_plan,
ensure_customer_does_not_have_active_plan,
get_latest_seat_count,
is_free_trial_offer_enabled,
is_sponsored_realm,
@ -169,7 +169,9 @@ def upgrade(
),
licenses: Optional[int] = REQ(json_validator=check_int, default=None),
) -> HttpResponse:
ensure_realm_does_not_have_active_plan(user.realm)
customer = get_customer_by_realm(user.realm)
if customer is not None:
ensure_customer_does_not_have_active_plan(customer)
try:
seat_count = unsign_seat_count(signed_seat_count, salt)
if billing_modality == "charge_automatically" and license_management == "automatic":
@ -178,7 +180,6 @@ def upgrade(
schedule = "annual"
license_management = "manual"
customer = get_customer_by_realm(user.realm)
exempt_from_license_number_check = (
customer is not None and customer.exempt_from_license_number_check
)