mirror of
https://github.com/zulip/zulip.git
synced 2025-11-09 16:37:23 +00:00
corporate: Move update_sponsorship_status to BillingSession class.
Moves `update_sponsorship_status` to BillingSession abstract class as `update_customer_sponsorship_status`. Updates the support views to have a helper for updating this on a realm: `update_realm_sponsorship_status`.
This commit is contained in:
committed by
Tim Abbott
parent
d06062c179
commit
5d07666362
@@ -6,7 +6,8 @@ import orjson
|
|||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
from corporate.lib.stripe import add_months, update_sponsorship_status
|
from corporate.lib.stripe import add_months
|
||||||
|
from corporate.lib.support import update_realm_sponsorship_status
|
||||||
from corporate.models import Customer, CustomerPlan, LicenseLedger, get_customer_by_realm
|
from corporate.models import Customer, CustomerPlan, LicenseLedger, get_customer_by_realm
|
||||||
from zerver.actions.invites import do_create_multiuse_invite_link
|
from zerver.actions.invites import do_create_multiuse_invite_link
|
||||||
from zerver.actions.realm_settings import do_change_realm_org_type, do_send_realm_reactivation_email
|
from zerver.actions.realm_settings import do_change_realm_org_type, do_send_realm_reactivation_email
|
||||||
@@ -558,8 +559,9 @@ class TestSupportEndpoint(ZulipTestCase):
|
|||||||
self.assertFalse(customer.sponsorship_pending)
|
self.assertFalse(customer.sponsorship_pending)
|
||||||
|
|
||||||
def test_approve_sponsorship(self) -> None:
|
def test_approve_sponsorship(self) -> None:
|
||||||
|
support_admin = self.example_user("iago")
|
||||||
lear_realm = get_realm("lear")
|
lear_realm = get_realm("lear")
|
||||||
update_sponsorship_status(lear_realm, True, acting_user=None)
|
update_realm_sponsorship_status(lear_realm, True, acting_user=support_admin)
|
||||||
king_user = self.lear_user("king")
|
king_user = self.lear_user("king")
|
||||||
king_user.role = UserProfile.ROLE_REALM_OWNER
|
king_user.role = UserProfile.ROLE_REALM_OWNER
|
||||||
king_user.save()
|
king_user.save()
|
||||||
|
|||||||
@@ -59,13 +59,13 @@ if settings.BILLING_ENABLED:
|
|||||||
make_end_of_cycle_updates_if_needed,
|
make_end_of_cycle_updates_if_needed,
|
||||||
switch_realm_from_standard_to_plus_plan,
|
switch_realm_from_standard_to_plus_plan,
|
||||||
update_billing_method_of_current_plan,
|
update_billing_method_of_current_plan,
|
||||||
update_sponsorship_status,
|
|
||||||
void_all_open_invoices,
|
void_all_open_invoices,
|
||||||
)
|
)
|
||||||
from corporate.lib.support import (
|
from corporate.lib.support import (
|
||||||
approve_realm_sponsorship,
|
approve_realm_sponsorship,
|
||||||
attach_discount_to_realm,
|
attach_discount_to_realm,
|
||||||
get_discount_for_realm,
|
get_discount_for_realm,
|
||||||
|
update_realm_sponsorship_status,
|
||||||
)
|
)
|
||||||
from corporate.models import (
|
from corporate.models import (
|
||||||
Customer,
|
Customer,
|
||||||
@@ -254,10 +254,10 @@ def support(
|
|||||||
] = f"Billing method of {realm.string_id} updated to charge automatically."
|
] = f"Billing method of {realm.string_id} updated to charge automatically."
|
||||||
elif sponsorship_pending is not None:
|
elif sponsorship_pending is not None:
|
||||||
if sponsorship_pending:
|
if sponsorship_pending:
|
||||||
update_sponsorship_status(realm, True, acting_user=acting_user)
|
update_realm_sponsorship_status(realm, True, acting_user=acting_user)
|
||||||
context["success_message"] = f"{realm.string_id} marked as pending sponsorship."
|
context["success_message"] = f"{realm.string_id} marked as pending sponsorship."
|
||||||
else:
|
else:
|
||||||
update_sponsorship_status(realm, False, acting_user=acting_user)
|
update_realm_sponsorship_status(realm, False, acting_user=acting_user)
|
||||||
context["success_message"] = f"{realm.string_id} is no longer pending sponsorship."
|
context["success_message"] = f"{realm.string_id} is no longer pending sponsorship."
|
||||||
elif approve_sponsorship:
|
elif approve_sponsorship:
|
||||||
approve_realm_sponsorship(realm, acting_user=acting_user)
|
approve_realm_sponsorship(realm, acting_user=acting_user)
|
||||||
|
|||||||
@@ -331,6 +331,7 @@ class AuditLogEventType(Enum):
|
|||||||
CUSTOMER_PLAN_CREATED = 3
|
CUSTOMER_PLAN_CREATED = 3
|
||||||
DISCOUNT_CHANGED = 4
|
DISCOUNT_CHANGED = 4
|
||||||
SPONSORSHIP_APPROVED = 5
|
SPONSORSHIP_APPROVED = 5
|
||||||
|
SPONSORSHIP_PENDING_STATUS_CHANGED = 6
|
||||||
|
|
||||||
|
|
||||||
class BillingSessionAuditLogEventError(Exception):
|
class BillingSessionAuditLogEventError(Exception):
|
||||||
@@ -450,6 +451,18 @@ class BillingSession(ABC):
|
|||||||
extra_data={"old_discount": old_discount, "new_discount": discount},
|
extra_data={"old_discount": old_discount, "new_discount": discount},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def update_customer_sponsorship_status(self, sponsorship_pending: bool) -> None:
|
||||||
|
customer = self.get_customer()
|
||||||
|
if customer is None:
|
||||||
|
customer = self.update_or_create_customer()
|
||||||
|
customer.sponsorship_pending = sponsorship_pending
|
||||||
|
customer.save(update_fields=["sponsorship_pending"])
|
||||||
|
self.write_to_audit_log(
|
||||||
|
event_type=AuditLogEventType.SPONSORSHIP_PENDING_STATUS_CHANGED,
|
||||||
|
event_time=timezone_now(),
|
||||||
|
extra_data={"sponsorship_pending": sponsorship_pending},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RealmBillingSession(BillingSession):
|
class RealmBillingSession(BillingSession):
|
||||||
def __init__(self, user: UserProfile, realm: Optional[Realm] = None) -> None:
|
def __init__(self, user: UserProfile, realm: Optional[Realm] = None) -> None:
|
||||||
@@ -478,6 +491,8 @@ class RealmBillingSession(BillingSession):
|
|||||||
return RealmAuditLog.REALM_DISCOUNT_CHANGED
|
return RealmAuditLog.REALM_DISCOUNT_CHANGED
|
||||||
elif event_type is AuditLogEventType.SPONSORSHIP_APPROVED:
|
elif event_type is AuditLogEventType.SPONSORSHIP_APPROVED:
|
||||||
return RealmAuditLog.REALM_SPONSORSHIP_APPROVED
|
return RealmAuditLog.REALM_SPONSORSHIP_APPROVED
|
||||||
|
elif event_type is AuditLogEventType.SPONSORSHIP_PENDING_STATUS_CHANGED:
|
||||||
|
return RealmAuditLog.REALM_SPONSORSHIP_PENDING_STATUS_CHANGED
|
||||||
else:
|
else:
|
||||||
raise BillingSessionAuditLogEventError(event_type)
|
raise BillingSessionAuditLogEventError(event_type)
|
||||||
|
|
||||||
@@ -1124,21 +1139,6 @@ def is_realm_on_free_trial(realm: Realm) -> bool:
|
|||||||
return plan is not None and plan.is_free_trial()
|
return plan is not None and plan.is_free_trial()
|
||||||
|
|
||||||
|
|
||||||
def update_sponsorship_status(
|
|
||||||
realm: Realm, sponsorship_pending: bool, *, acting_user: Optional[UserProfile]
|
|
||||||
) -> None:
|
|
||||||
customer, _ = Customer.objects.get_or_create(realm=realm)
|
|
||||||
customer.sponsorship_pending = sponsorship_pending
|
|
||||||
customer.save(update_fields=["sponsorship_pending"])
|
|
||||||
RealmAuditLog.objects.create(
|
|
||||||
realm=realm,
|
|
||||||
acting_user=acting_user,
|
|
||||||
event_type=RealmAuditLog.REALM_SPONSORSHIP_PENDING_STATUS_CHANGED,
|
|
||||||
event_time=timezone_now(),
|
|
||||||
extra_data={"sponsorship_pending": sponsorship_pending},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_sponsored_realm(realm: Realm) -> bool:
|
def is_sponsored_realm(realm: Realm) -> bool:
|
||||||
return realm.plan_type == Realm.PLAN_TYPE_STANDARD_FREE
|
return realm.plan_type == Realm.PLAN_TYPE_STANDARD_FREE
|
||||||
|
|
||||||
|
|||||||
@@ -34,3 +34,10 @@ def attach_discount_to_realm(realm: Realm, discount: Decimal, *, acting_user: Us
|
|||||||
def approve_realm_sponsorship(realm: Realm, *, acting_user: UserProfile) -> None:
|
def approve_realm_sponsorship(realm: Realm, *, acting_user: UserProfile) -> None:
|
||||||
billing_session = RealmBillingSession(acting_user, realm)
|
billing_session = RealmBillingSession(acting_user, realm)
|
||||||
billing_session.approve_sponsorship()
|
billing_session.approve_sponsorship()
|
||||||
|
|
||||||
|
|
||||||
|
def update_realm_sponsorship_status(
|
||||||
|
realm: Realm, sponsorship_pending: bool, *, acting_user: UserProfile
|
||||||
|
) -> None:
|
||||||
|
billing_session = RealmBillingSession(acting_user, realm)
|
||||||
|
billing_session.update_customer_sponsorship_status(sponsorship_pending)
|
||||||
|
|||||||
@@ -76,13 +76,13 @@ from corporate.lib.stripe import (
|
|||||||
update_license_ledger_for_automanaged_plan,
|
update_license_ledger_for_automanaged_plan,
|
||||||
update_license_ledger_for_manual_plan,
|
update_license_ledger_for_manual_plan,
|
||||||
update_license_ledger_if_needed,
|
update_license_ledger_if_needed,
|
||||||
update_sponsorship_status,
|
|
||||||
void_all_open_invoices,
|
void_all_open_invoices,
|
||||||
)
|
)
|
||||||
from corporate.lib.support import (
|
from corporate.lib.support import (
|
||||||
approve_realm_sponsorship,
|
approve_realm_sponsorship,
|
||||||
attach_discount_to_realm,
|
attach_discount_to_realm,
|
||||||
get_discount_for_realm,
|
get_discount_for_realm,
|
||||||
|
update_realm_sponsorship_status,
|
||||||
)
|
)
|
||||||
from corporate.models import (
|
from corporate.models import (
|
||||||
Customer,
|
Customer,
|
||||||
@@ -2475,21 +2475,6 @@ class StripeTest(StripeTestCase):
|
|||||||
# card on file, and should show it
|
# card on file, and should show it
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
def test_update_sponsorship_status(self) -> None:
|
|
||||||
lear = get_realm("lear")
|
|
||||||
iago = self.example_user("iago")
|
|
||||||
update_sponsorship_status(lear, True, acting_user=iago)
|
|
||||||
customer = get_customer_by_realm(realm=lear)
|
|
||||||
assert customer is not None
|
|
||||||
self.assertTrue(customer.sponsorship_pending)
|
|
||||||
realm_audit_log = RealmAuditLog.objects.filter(
|
|
||||||
event_type=RealmAuditLog.REALM_SPONSORSHIP_PENDING_STATUS_CHANGED
|
|
||||||
).last()
|
|
||||||
assert realm_audit_log is not None
|
|
||||||
expected_extra_data = {"sponsorship_pending": True}
|
|
||||||
self.assertEqual(realm_audit_log.extra_data, expected_extra_data)
|
|
||||||
self.assertEqual(realm_audit_log.acting_user, iago)
|
|
||||||
|
|
||||||
@mock_stripe()
|
@mock_stripe()
|
||||||
def test_replace_payment_method(self, *mocks: Mock) -> None:
|
def test_replace_payment_method(self, *mocks: Mock) -> None:
|
||||||
user = self.example_user("hamlet")
|
user = self.example_user("hamlet")
|
||||||
@@ -5062,3 +5047,18 @@ class TestSupportBillingHelpers(StripeTestCase):
|
|||||||
self.assertEqual(message.content, expected_message)
|
self.assertEqual(message.content, expected_message)
|
||||||
self.assertEqual(message.recipient.type, Recipient.PERSONAL)
|
self.assertEqual(message.recipient.type, Recipient.PERSONAL)
|
||||||
self.assertEqual(message.recipient_id, recipient_id)
|
self.assertEqual(message.recipient_id, recipient_id)
|
||||||
|
|
||||||
|
def test_update_realm_sponsorship_status(self) -> None:
|
||||||
|
lear = get_realm("lear")
|
||||||
|
iago = self.example_user("iago")
|
||||||
|
update_realm_sponsorship_status(lear, True, acting_user=iago)
|
||||||
|
customer = get_customer_by_realm(realm=lear)
|
||||||
|
assert customer is not None
|
||||||
|
self.assertTrue(customer.sponsorship_pending)
|
||||||
|
realm_audit_log = RealmAuditLog.objects.filter(
|
||||||
|
event_type=RealmAuditLog.REALM_SPONSORSHIP_PENDING_STATUS_CHANGED
|
||||||
|
).last()
|
||||||
|
assert realm_audit_log is not None
|
||||||
|
expected_extra_data = {"sponsorship_pending": True}
|
||||||
|
self.assertEqual(realm_audit_log.extra_data, expected_extra_data)
|
||||||
|
self.assertEqual(realm_audit_log.acting_user, iago)
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ from corporate.lib.stripe import (
|
|||||||
process_initial_upgrade,
|
process_initial_upgrade,
|
||||||
sign_string,
|
sign_string,
|
||||||
unsign_string,
|
unsign_string,
|
||||||
update_sponsorship_status,
|
|
||||||
validate_licenses,
|
validate_licenses,
|
||||||
)
|
)
|
||||||
from corporate.lib.support import get_support_url
|
from corporate.lib.support import get_support_url
|
||||||
@@ -325,6 +324,7 @@ def sponsorship(
|
|||||||
description: str = REQ(),
|
description: str = REQ(),
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
realm = user.realm
|
realm = user.realm
|
||||||
|
billing_session = RealmBillingSession(user)
|
||||||
|
|
||||||
requested_by = user.full_name
|
requested_by = user.full_name
|
||||||
user_role = user.get_role_name()
|
user_role = user.get_role_name()
|
||||||
@@ -353,7 +353,7 @@ def sponsorship(
|
|||||||
realm.org_type = org_type
|
realm.org_type = org_type
|
||||||
realm.save(update_fields=["org_type"])
|
realm.save(update_fields=["org_type"])
|
||||||
|
|
||||||
update_sponsorship_status(realm, True, acting_user=user)
|
billing_session.update_customer_sponsorship_status(True)
|
||||||
do_make_user_billing_admin(user)
|
do_make_user_billing_admin(user)
|
||||||
|
|
||||||
org_type_display_name = get_org_type_display_name(org_type)
|
org_type_display_name = get_org_type_display_name(org_type)
|
||||||
|
|||||||
Reference in New Issue
Block a user