mirror of https://github.com/zulip/zulip.git
billing: Rename get_seat_count to get_latest_seat_count.
This will help as our billing system becomes more async to accommodate on-prem billing.
This commit is contained in:
parent
bea9e41fbd
commit
0b39263ec0
|
@ -38,7 +38,7 @@ CallableT = TypeVar('CallableT', bound=Callable[..., Any])
|
|||
MIN_INVOICED_LICENSES = 30
|
||||
DEFAULT_INVOICE_DAYS_UNTIL_DUE = 30
|
||||
|
||||
def get_seat_count(realm: Realm) -> int:
|
||||
def get_latest_seat_count(realm: Realm) -> int:
|
||||
non_guests = UserProfile.objects.filter(
|
||||
realm=realm, is_active=True, is_bot=False).exclude(role=UserProfile.ROLE_GUEST).count()
|
||||
guests = UserProfile.objects.filter(
|
||||
|
@ -314,7 +314,7 @@ def process_initial_upgrade(user: UserProfile, licenses: int, automanage_license
|
|||
with transaction.atomic():
|
||||
# billed_licenses can greater than licenses if users are added between the start of
|
||||
# this function (process_initial_upgrade) and now
|
||||
billed_licenses = max(get_seat_count(realm), licenses)
|
||||
billed_licenses = max(get_latest_seat_count(realm), licenses)
|
||||
plan_params = {
|
||||
'automanage_licenses': automanage_licenses,
|
||||
'charge_automatically': charge_automatically,
|
||||
|
@ -371,7 +371,7 @@ def update_license_ledger_for_automanaged_plan(realm: Realm, plan: CustomerPlan,
|
|||
last_ledger_entry = make_end_of_cycle_updates_if_needed(plan, event_time)
|
||||
if last_ledger_entry is None:
|
||||
return
|
||||
licenses_at_next_renewal = get_seat_count(realm)
|
||||
licenses_at_next_renewal = get_latest_seat_count(realm)
|
||||
licenses = max(licenses_at_next_renewal, last_ledger_entry.licenses)
|
||||
LicenseLedger.objects.create(
|
||||
plan=plan, event_time=event_time, licenses=licenses,
|
||||
|
|
|
@ -23,7 +23,7 @@ from zerver.lib.test_classes import ZulipTestCase
|
|||
from zerver.lib.timestamp import timestamp_to_datetime, datetime_to_timestamp
|
||||
from zerver.models import Realm, UserProfile, get_realm, RealmAuditLog
|
||||
from corporate.lib.stripe import catch_stripe_errors, attach_discount_to_realm, \
|
||||
get_seat_count, sign_string, unsign_string, \
|
||||
get_latest_seat_count, sign_string, unsign_string, \
|
||||
BillingError, StripeCardError, stripe_get_customer, \
|
||||
MIN_INVOICED_LICENSES, \
|
||||
add_months, next_month, \
|
||||
|
@ -215,9 +215,9 @@ class StripeTestCase(ZulipTestCase):
|
|||
def setUp(self, *mocks: Mock) -> None:
|
||||
super().setUp()
|
||||
# This test suite is not robust to users being added in populate_db. The following
|
||||
# hack ensures get_seat_count is fixed, even as populate_db changes.
|
||||
# hack ensures get_latest_seat_count is fixed, even as populate_db changes.
|
||||
realm = get_realm('zulip')
|
||||
seat_count = get_seat_count(realm)
|
||||
seat_count = get_latest_seat_count(realm)
|
||||
assert(seat_count >= 6)
|
||||
for user in UserProfile.objects.filter(realm=realm, is_active=True, is_bot=False) \
|
||||
.exclude(role=UserProfile.ROLE_GUEST).exclude(email__in=[
|
||||
|
@ -225,7 +225,7 @@ class StripeTestCase(ZulipTestCase):
|
|||
self.example_email('iago')])[:seat_count-6]:
|
||||
user.is_active = False
|
||||
user.save(update_fields=['is_active'])
|
||||
self.assertEqual(get_seat_count(realm), 6)
|
||||
self.assertEqual(get_latest_seat_count(realm), 6)
|
||||
self.seat_count = 6
|
||||
self.signed_seat_count, self.salt = sign_string(str(self.seat_count))
|
||||
# Choosing dates with corresponding timestamps below 1500000000 so that they are
|
||||
|
@ -544,7 +544,7 @@ class StripeTest(StripeTestCase):
|
|||
self.login(self.example_email("hamlet"))
|
||||
new_seat_count = 23
|
||||
# Change the seat count while the user is going through the upgrade flow
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=new_seat_count):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=new_seat_count):
|
||||
self.upgrade()
|
||||
stripe_customer_id = Customer.objects.first().stripe_customer_id
|
||||
# Check that the Charge used the old quantity, not new_seat_count
|
||||
|
@ -592,8 +592,8 @@ class StripeTest(StripeTestCase):
|
|||
self.assertEqual('/upgrade/', response.url)
|
||||
|
||||
# Try again, with a valid card, after they added a few users
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=23):
|
||||
with patch('corporate.views.get_seat_count', return_value=23):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=23):
|
||||
with patch('corporate.views.get_latest_seat_count', return_value=23):
|
||||
self.upgrade()
|
||||
customer = Customer.objects.get(realm=get_realm('zulip'))
|
||||
# It's impossible to create two Customers, but check that we didn't
|
||||
|
@ -723,37 +723,37 @@ class StripeTest(StripeTestCase):
|
|||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual('/upgrade/', response.url)
|
||||
|
||||
def test_get_seat_count(self) -> None:
|
||||
def test_get_latest_seat_count(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
initial_count = get_seat_count(realm)
|
||||
initial_count = get_latest_seat_count(realm)
|
||||
user1 = UserProfile.objects.create(realm=realm, email='user1@zulip.com', pointer=-1)
|
||||
user2 = UserProfile.objects.create(realm=realm, email='user2@zulip.com', pointer=-1)
|
||||
self.assertEqual(get_seat_count(realm), initial_count + 2)
|
||||
self.assertEqual(get_latest_seat_count(realm), initial_count + 2)
|
||||
|
||||
# Test that bots aren't counted
|
||||
user1.is_bot = True
|
||||
user1.save(update_fields=['is_bot'])
|
||||
self.assertEqual(get_seat_count(realm), initial_count + 1)
|
||||
self.assertEqual(get_latest_seat_count(realm), initial_count + 1)
|
||||
|
||||
# Test that inactive users aren't counted
|
||||
do_deactivate_user(user2)
|
||||
self.assertEqual(get_seat_count(realm), initial_count)
|
||||
self.assertEqual(get_latest_seat_count(realm), initial_count)
|
||||
|
||||
# Test guests
|
||||
# Adding a guest to a realm with a lot of members shouldn't change anything
|
||||
UserProfile.objects.create(realm=realm, email='user3@zulip.com', pointer=-1, role=UserProfile.ROLE_GUEST)
|
||||
self.assertEqual(get_seat_count(realm), initial_count)
|
||||
self.assertEqual(get_latest_seat_count(realm), initial_count)
|
||||
# Test 1 member and 5 guests
|
||||
realm = Realm.objects.create(string_id='second', name='second')
|
||||
UserProfile.objects.create(realm=realm, email='member@second.com', pointer=-1)
|
||||
for i in range(5):
|
||||
UserProfile.objects.create(realm=realm, email='guest{}@second.com'.format(i),
|
||||
pointer=-1, role=UserProfile.ROLE_GUEST)
|
||||
self.assertEqual(get_seat_count(realm), 1)
|
||||
self.assertEqual(get_latest_seat_count(realm), 1)
|
||||
# Test 1 member and 6 guests
|
||||
UserProfile.objects.create(realm=realm, email='guest5@second.com', pointer=-1,
|
||||
role=UserProfile.ROLE_GUEST)
|
||||
self.assertEqual(get_seat_count(realm), 2)
|
||||
self.assertEqual(get_latest_seat_count(realm), 2)
|
||||
|
||||
def test_sign_string(self) -> None:
|
||||
string = "abc"
|
||||
|
@ -892,7 +892,7 @@ class StripeTest(StripeTestCase):
|
|||
|
||||
# Verify that we still write LicenseLedger rows during the remaining
|
||||
# part of the cycle
|
||||
with patch("corporate.lib.stripe.get_seat_count", return_value=20):
|
||||
with patch("corporate.lib.stripe.get_latest_seat_count", return_value=20):
|
||||
update_license_ledger_if_needed(user.realm, self.now)
|
||||
self.assertEqual(LicenseLedger.objects.order_by('-id').values_list(
|
||||
'licenses', 'licenses_at_next_renewal').first(), (20, 20))
|
||||
|
@ -907,7 +907,7 @@ class StripeTest(StripeTestCase):
|
|||
mocked.reset_mock()
|
||||
|
||||
# Check that we downgrade properly if the cycle is over
|
||||
with patch("corporate.lib.stripe.get_seat_count", return_value=30):
|
||||
with patch("corporate.lib.stripe.get_latest_seat_count", return_value=30):
|
||||
update_license_ledger_if_needed(user.realm, self.next_year)
|
||||
self.assertEqual(get_realm('zulip').plan_type, Realm.LIMITED)
|
||||
self.assertEqual(CustomerPlan.objects.first().status, CustomerPlan.ENDED)
|
||||
|
@ -915,7 +915,7 @@ class StripeTest(StripeTestCase):
|
|||
'licenses', 'licenses_at_next_renewal').first(), (20, 20))
|
||||
|
||||
# Verify that we don't write LicenseLedger rows once we've downgraded
|
||||
with patch("corporate.lib.stripe.get_seat_count", return_value=40):
|
||||
with patch("corporate.lib.stripe.get_latest_seat_count", return_value=40):
|
||||
update_license_ledger_if_needed(user.realm, self.next_year)
|
||||
self.assertEqual(LicenseLedger.objects.order_by('-id').values_list(
|
||||
'licenses', 'licenses_at_next_renewal').first(), (20, 20))
|
||||
|
@ -931,7 +931,7 @@ class StripeTest(StripeTestCase):
|
|||
self.assertIsNone(CustomerPlan.objects.first().next_invoice_date)
|
||||
|
||||
# Check that we don't call invoice_plan after that final call
|
||||
with patch("corporate.lib.stripe.get_seat_count", return_value=50):
|
||||
with patch("corporate.lib.stripe.get_latest_seat_count", return_value=50):
|
||||
update_license_ledger_if_needed(user.realm, self.next_year + timedelta(days=80))
|
||||
with patch("corporate.lib.stripe.invoice_plan") as mocked:
|
||||
invoice_plans_as_needed(self.next_year + timedelta(days=400))
|
||||
|
@ -1141,16 +1141,16 @@ class LicenseLedgerTest(StripeTestCase):
|
|||
self.local_upgrade(self.seat_count, True, CustomerPlan.ANNUAL, 'token')
|
||||
plan = CustomerPlan.objects.first()
|
||||
# Simple increase
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=23):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=23):
|
||||
update_license_ledger_for_automanaged_plan(realm, plan, self.now)
|
||||
# Decrease
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=20):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=20):
|
||||
update_license_ledger_for_automanaged_plan(realm, plan, self.now)
|
||||
# Increase, but not past high watermark
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=21):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=21):
|
||||
update_license_ledger_for_automanaged_plan(realm, plan, self.now)
|
||||
# Increase, but after renewal date, and below last year's high watermark
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=22):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=22):
|
||||
update_license_ledger_for_automanaged_plan(realm, plan, self.next_year + timedelta(seconds=1))
|
||||
|
||||
ledger_entries = list(LicenseLedger.objects.values_list(
|
||||
|
@ -1195,19 +1195,19 @@ class InvoiceTest(StripeTestCase):
|
|||
with patch('corporate.lib.stripe.timezone_now', return_value=self.now):
|
||||
self.upgrade()
|
||||
# Increase
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=self.seat_count + 3):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=self.seat_count + 3):
|
||||
update_license_ledger_if_needed(get_realm('zulip'), self.now + timedelta(days=100))
|
||||
# Decrease
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=self.seat_count):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=self.seat_count):
|
||||
update_license_ledger_if_needed(get_realm('zulip'), self.now + timedelta(days=200))
|
||||
# Increase, but not past high watermark
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=self.seat_count + 1):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=self.seat_count + 1):
|
||||
update_license_ledger_if_needed(get_realm('zulip'), self.now + timedelta(days=300))
|
||||
# Increase, but after renewal date, and below last year's high watermark
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=self.seat_count + 2):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=self.seat_count + 2):
|
||||
update_license_ledger_if_needed(get_realm('zulip'), self.now + timedelta(days=400))
|
||||
# Increase, but after event_time
|
||||
with patch('corporate.lib.stripe.get_seat_count', return_value=self.seat_count + 3):
|
||||
with patch('corporate.lib.stripe.get_latest_seat_count', return_value=self.seat_count + 3):
|
||||
update_license_ledger_if_needed(get_realm('zulip'), self.now + timedelta(days=500))
|
||||
plan = CustomerPlan.objects.first()
|
||||
invoice_plan(plan, self.now + timedelta(days=400))
|
||||
|
|
|
@ -16,7 +16,7 @@ from zerver.lib.response import json_error, json_success
|
|||
from zerver.lib.validator import check_string, check_int
|
||||
from zerver.models import UserProfile
|
||||
from corporate.lib.stripe import STRIPE_PUBLISHABLE_KEY, \
|
||||
stripe_get_customer, get_seat_count, \
|
||||
stripe_get_customer, get_latest_seat_count, \
|
||||
process_initial_upgrade, sign_string, \
|
||||
unsign_string, BillingError, do_change_plan_status, do_replace_payment_source, \
|
||||
MIN_INVOICED_LICENSES, DEFAULT_INVOICE_DAYS_UNTIL_DUE, \
|
||||
|
@ -124,7 +124,7 @@ def initial_upgrade(request: HttpRequest) -> HttpResponse:
|
|||
if customer is not None and customer.default_discount is not None:
|
||||
percent_off = customer.default_discount
|
||||
|
||||
seat_count = get_seat_count(user.realm)
|
||||
seat_count = get_latest_seat_count(user.realm)
|
||||
signed_seat_count, salt = sign_string(str(seat_count))
|
||||
context = {
|
||||
'publishable_key': STRIPE_PUBLISHABLE_KEY,
|
||||
|
@ -177,7 +177,7 @@ def billing_home(request: HttpRequest) -> HttpResponse:
|
|||
last_ledger_entry = make_end_of_cycle_updates_if_needed(plan, now)
|
||||
if last_ledger_entry is not None:
|
||||
licenses = last_ledger_entry.licenses
|
||||
licenses_used = get_seat_count(user.realm)
|
||||
licenses_used = get_latest_seat_count(user.realm)
|
||||
# Should do this in javascript, using the user's timezone
|
||||
renewal_date = '{dt:%B} {dt.day}, {dt.year}'.format(dt=start_of_next_billing_cycle(plan, now))
|
||||
renewal_cents = renewal_amount(plan, now)
|
||||
|
|
Loading…
Reference in New Issue