billing: Refactor BillingError to subclass JsonableError.

This lets us remove unnecessary BillingError to json_error conversion
code.
This commit is contained in:
PIG208 2021-07-04 14:19:18 +08:00 committed by Tim Abbott
parent 53e2193b10
commit 72f9f964a1
3 changed files with 30 additions and 33 deletions

View File

@ -26,6 +26,7 @@ from corporate.models import (
get_current_plan_by_realm,
get_customer_by_realm,
)
from zerver.lib.exceptions import JsonableError
from zerver.lib.logging_util import log_to_file
from zerver.lib.send_email import FromAddress, send_email_to_billing_admins_and_realm_owners
from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime
@ -196,17 +197,18 @@ def cents_to_dollar_string(cents: int) -> str:
return f"{cents / 100.:,.2f}"
class BillingError(Exception):
class BillingError(JsonableError):
data_fields = ["error_description"]
# error messages
CONTACT_SUPPORT = gettext_lazy("Something went wrong. Please contact {email}.")
TRY_RELOADING = gettext_lazy("Something went wrong. Please reload the page.")
# description is used only for tests
def __init__(self, description: str, message: Optional[str] = None) -> None:
self.description = description
self.error_description = description
if message is None:
message = BillingError.CONTACT_SUPPORT.format(email=settings.ZULIP_ADMINISTRATOR)
self.message = message
super().__init__(message)
class LicenseLimitError(Exception):

View File

@ -464,7 +464,7 @@ class StripeTest(StripeTestCase):
with self.assertLogs("corporate.stripe", "ERROR") as error_log:
with self.assertRaises(BillingError) as context:
raise_invalid_request_error()
self.assertEqual("other stripe error", context.exception.description)
self.assertEqual("other stripe error", context.exception.error_description)
self.assertEqual(
error_log.output, ["ERROR:corporate.stripe:Stripe error: None None None None"]
)
@ -480,8 +480,8 @@ class StripeTest(StripeTestCase):
with self.assertLogs("corporate.stripe", "INFO") as info_log:
with self.assertRaises(StripeCardError) as context:
raise_card_error()
self.assertIn("not a valid credit card", context.exception.message)
self.assertEqual("card error", context.exception.description)
self.assertIn("not a valid credit card", str(context.exception))
self.assertEqual("card error", context.exception.error_description)
self.assertEqual(
info_log.output, ["INFO:corporate.stripe:Stripe card error: None None None None"]
)
@ -1305,7 +1305,9 @@ class StripeTest(StripeTestCase):
with self.assertLogs("corporate.stripe", "WARNING") as m:
with self.assertRaises(BillingError) as context:
self.local_upgrade(self.seat_count, True, CustomerPlan.ANNUAL, "token")
self.assertEqual("subscribing with existing subscription", context.exception.description)
self.assertEqual(
"subscribing with existing subscription", context.exception.error_description
)
self.assertEqual(
m.output[0],
f"WARNING:corporate.stripe:Customer <Customer <Realm: zulip {hamlet.realm.id}> id> trying to upgrade, but has an active subscription",
@ -2336,7 +2338,9 @@ class StripeTest(StripeTestCase):
m.output[0],
f"WARNING:corporate.stripe:Customer <Customer <Realm: zulip {user.realm.id}> id> trying to upgrade, but has an active subscription",
)
self.assertEqual(context.exception.description, "subscribing with existing subscription")
self.assertEqual(
context.exception.error_description, "subscribing with existing subscription"
)
invoice_plans_as_needed(self.next_year)
@ -3384,10 +3388,12 @@ class InvoiceTest(StripeTestCase):
assert plan and plan.customer
plan.customer.stripe_customer_id = None
plan.customer.save(update_fields=["stripe_customer_id"])
with self.assertRaisesRegex(
BillingError, "Realm zulip has a paid plan without a Stripe customer"
):
with self.assertRaises(BillingError) as context:
invoice_plan(plan, timezone_now())
self.assertRegex(
context.exception.error_description,
"Realm zulip has a paid plan without a Stripe customer",
)
@mock_stripe()
def test_invoice_plan(self, *mocks: Mock) -> None:

View File

@ -49,7 +49,7 @@ from zerver.decorator import (
from zerver.lib.actions import do_make_user_billing_admin
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success
from zerver.lib.response import json_success
from zerver.lib.send_email import FromAddress, send_email
from zerver.lib.validator import check_int, check_int_in, check_string_in
from zerver.models import UserProfile, get_realm
@ -156,7 +156,7 @@ def upgrade(
billing_logger.warning(
"BillingError during upgrade: %s. user=%s, realm=%s (%s), billing_modality=%s, "
"schedule=%s, license_management=%s, licenses=%s, has stripe_token: %s",
e.description,
e.error_description,
user.id,
user.realm.id,
user.realm.string_id,
@ -166,12 +166,12 @@ def upgrade(
licenses,
stripe_token is not None,
)
return json_error(e.message, data={"error_description": e.description})
raise
except Exception:
billing_logger.exception("Uncaught exception in billing:", stack_info=True)
error_message = BillingError.CONTACT_SUPPORT.format(email=settings.ZULIP_ADMINISTRATOR)
error_description = "uncaught exception during upgrade"
return json_error(error_message, data={"error_description": error_description})
raise BillingError(error_description, error_message)
else:
return json_success()
@ -417,12 +417,7 @@ def update_plan(
licenses=licenses
)
)
try:
validate_licenses(
plan.charge_automatically, licenses, get_latest_seat_count(user.realm)
)
except BillingError as e:
return json_error(e.message, data={"error_description": e.description})
validate_licenses(plan.charge_automatically, licenses, get_latest_seat_count(user.realm))
update_license_ledger_for_manual_plan(plan, timezone_now(), licenses=licenses)
return json_success()
@ -439,14 +434,11 @@ def update_plan(
"Your plan is already scheduled to renew with {licenses_at_next_renewal} licenses."
).format(licenses_at_next_renewal=licenses_at_next_renewal)
)
try:
validate_licenses(
plan.charge_automatically,
licenses_at_next_renewal,
get_latest_seat_count(user.realm),
)
except BillingError as e:
return json_error(e.message, data={"error_description": e.description})
validate_licenses(
plan.charge_automatically,
licenses_at_next_renewal,
get_latest_seat_count(user.realm),
)
update_license_ledger_for_manual_plan(
plan, timezone_now(), licenses_at_next_renewal=licenses_at_next_renewal
)
@ -462,8 +454,5 @@ def replace_payment_source(
user: UserProfile,
stripe_token: str = REQ(),
) -> HttpResponse:
try:
do_replace_payment_source(user, stripe_token, pay_invoices=True)
except BillingError as e:
return json_error(e.message, data={"error_description": e.description})
do_replace_payment_source(user, stripe_token, pay_invoices=True)
return json_success()