billing: Fix license counting in exempt_from_license_number_check case.

Fixes two bugs involving organization with
exempt_from_license_number_check enabled:
1. If the organization had e.g. 100 users and upgraded their plan,
   specifying 50 licenses, the generated LicenseLedger and thus the
   corresponding invoice was still for 100 users.
2. The organization was unable to use the billing/plan endpoint (update
   plan endpoint) to make their number of licenses less than the current
   number of users.

Organizations with exempt_from_license_number_check are supposed to be
able to declare whatever license number they want, as this attribute
allows having pricing schemes where an organization only pays us for a
subset of their users.
This commit is contained in:
Mateusz Mandera
2023-09-26 01:57:58 +02:00
committed by Tim Abbott
parent 1de3a9f4a3
commit 07e99eace9
2 changed files with 66 additions and 5 deletions

View File

@@ -700,9 +700,12 @@ def process_initial_upgrade(
# TODO: The correctness of this relies on user creation, deactivation, etc being
# in a transaction.atomic() with the relevant RealmAuditLog entries
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_latest_seat_count(realm), licenses)
if customer.exempt_from_license_number_check:
billed_licenses = licenses
else:
# billed_licenses can be greater than licenses if users are added between the start of
# this function (process_initial_upgrade) and now
billed_licenses = max(get_latest_seat_count(realm), licenses)
plan_params = {
"automanage_licenses": automanage_licenses,
"charge_automatically": charge_automatically,
@@ -777,14 +780,16 @@ def update_license_ledger_for_manual_plan(
) -> None:
if licenses is not None:
assert plan.customer.realm is not None
assert get_latest_seat_count(plan.customer.realm) <= licenses
if not plan.customer.exempt_from_license_number_check:
assert get_latest_seat_count(plan.customer.realm) <= licenses
assert licenses > plan.licenses()
LicenseLedger.objects.create(
plan=plan, event_time=event_time, licenses=licenses, licenses_at_next_renewal=licenses
)
elif licenses_at_next_renewal is not None:
assert plan.customer.realm is not None
assert get_latest_seat_count(plan.customer.realm) <= licenses_at_next_renewal
if not plan.customer.exempt_from_license_number_check:
assert get_latest_seat_count(plan.customer.realm) <= licenses_at_next_renewal
LicenseLedger.objects.create(
plan=plan,
event_time=event_time,