support: Extract PlanData as a dataclass.

This avoids monkey-patching `CustomerPlan` and other related information
onto the `Realm` object by having a separate dictionary with the realm
id as the key, each corresponds to a `PlandData` dataclass.

This is a part of the django-stubs refactorings.

Signed-off-by: Zixuan James Li <p359101898@gmail.com>
This commit is contained in:
Zixuan James Li
2022-06-30 11:36:52 -04:00
committed by Tim Abbott
parent 74f59bd8d0
commit 0d93257111
2 changed files with 35 additions and 22 deletions

View File

@@ -1,4 +1,5 @@
import urllib import urllib
from dataclasses import dataclass
from datetime import timedelta from datetime import timedelta
from decimal import Decimal from decimal import Decimal
from typing import Any, Dict, Iterable, List, Optional from typing import Any, Dict, Iterable, List, Optional
@@ -16,6 +17,7 @@ from django.utils.translation import gettext as _
from confirmation.models import Confirmation, confirmation_url from confirmation.models import Confirmation, confirmation_url
from confirmation.settings import STATUS_ACTIVE from confirmation.settings import STATUS_ACTIVE
from corporate.models import Customer, CustomerPlan
from zerver.actions.create_realm import do_change_realm_subdomain from zerver.actions.create_realm import do_change_realm_subdomain
from zerver.actions.realm_settings import ( from zerver.actions.realm_settings import (
do_change_realm_org_type, do_change_realm_org_type,
@@ -129,6 +131,14 @@ VALID_BILLING_METHODS = [
] ]
@dataclass
class PlanData:
customer: Optional[Customer] = None
current_plan: Optional[CustomerPlan] = None
licenses: Optional[int] = None
licenses_used: Optional[int] = None
@require_server_admin @require_server_admin
@has_request_variables @has_request_variables
def support( def support(
@@ -277,27 +287,30 @@ def support(
except ValidationError: except ValidationError:
users.update(UserProfile.objects.filter(full_name__iexact=key_word)) users.update(UserProfile.objects.filter(full_name__iexact=key_word))
plan_data: Dict[int, PlanData] = {}
for realm in realms: for realm in realms:
realm.customer = get_customer_by_realm(realm)
current_plan = get_current_plan_by_realm(realm) current_plan = get_current_plan_by_realm(realm)
plan_data[realm.id] = PlanData(
customer=get_customer_by_realm(realm),
current_plan=current_plan,
)
if current_plan is not None: if current_plan is not None:
new_plan, last_ledger_entry = make_end_of_cycle_updates_if_needed( new_plan, last_ledger_entry = make_end_of_cycle_updates_if_needed(
current_plan, timezone_now() current_plan, timezone_now()
) )
if last_ledger_entry is not None: if last_ledger_entry is not None:
if new_plan is not None: if new_plan is not None:
realm.current_plan = new_plan plan_data[realm.id].current_plan = new_plan
else: else:
realm.current_plan = current_plan plan_data[realm.id].current_plan = current_plan
realm.current_plan.licenses = last_ledger_entry.licenses plan_data[realm.id].licenses = last_ledger_entry.licenses
realm.current_plan.licenses_used = get_latest_seat_count(realm) plan_data[realm.id].licenses_used = get_latest_seat_count(realm)
# full_names can have , in them # full_names can have , in them
users.update(UserProfile.objects.filter(full_name__iexact=query)) users.update(UserProfile.objects.filter(full_name__iexact=query))
context["users"] = users context["users"] = users
context["realms"] = realms context["realms"] = realms
context["plan_data"] = plan_data
confirmations: List[Dict[str, Any]] = [] confirmations: List[Dict[str, Any]] = []

View File

@@ -80,13 +80,13 @@
{{ csrf_input }} {{ csrf_input }}
<input type="hidden" name="realm_id" value="{{ realm.id }}" /> <input type="hidden" name="realm_id" value="{{ realm.id }}" />
<select name="sponsorship_pending"> <select name="sponsorship_pending">
<option value="true" {% if realm.customer and realm.customer.sponsorship_pending %}selected{% endif %}>Yes</option> <option value="true" {% if plan_data[realm.id].customer and plan_data[realm.id].customer.sponsorship_pending %}selected{% endif %}>Yes</option>
<option value="false" {% if not realm.customer or not realm.customer.sponsorship_pending %}selected{% endif %}>No</option> <option value="false" {% if not plan_data[realm.id].customer or not plan_data[realm.id].customer.sponsorship_pending %}selected{% endif %}>No</option>
</select> </select>
<button type="submit" class="btn btn-default support-submit-button">Update</button> <button type="submit" class="btn btn-default support-submit-button">Update</button>
</form> </form>
{% if realm.customer and realm.customer.sponsorship_pending %} {% if plan_data[realm.id].customer and plan_data[realm.id].customer.sponsorship_pending %}
<form method="POST" class="approve-sponsorship-form"> <form method="POST" class="approve-sponsorship-form">
{{ csrf_input }} {{ csrf_input }}
<input type="hidden" name="realm_id" value="{{ realm.id }}" /> <input type="hidden" name="realm_id" value="{{ realm.id }}" />
@@ -102,7 +102,7 @@
<b>Discount (use 85 for nonprofits)</b>:<br /> <b>Discount (use 85 for nonprofits)</b>:<br />
{{ csrf_input }} {{ csrf_input }}
<input type="hidden" name="realm_id" value="{{ realm.id }}" /> <input type="hidden" name="realm_id" value="{{ realm.id }}" />
{% if realm.current_plan and realm.current_plan.fixed_price %} {% if plan_data[realm.id].current_plan and plan_data[realm.id].current_plan.fixed_price %}
<input type="number" name="discount" value="{{ get_discount_for_realm(realm) }}" disabled /> <input type="number" name="discount" value="{{ get_discount_for_realm(realm) }}" disabled />
<button type="submit" class="btn btn-default support-submit-button" disabled>Update</button> <button type="submit" class="btn btn-default support-submit-button" disabled>Update</button>
{% else %} {% else %}
@@ -110,19 +110,19 @@
<button type="submit" class="btn btn-default support-submit-button">Update</button> <button type="submit" class="btn btn-default support-submit-button">Update</button>
{% endif %} {% endif %}
</form> </form>
{% if realm.current_plan %} {% if plan_data[realm.id].current_plan %}
<div class="current-plan-details"> <div class="current-plan-details">
<h3>📅 Current plan</h3> <h3>📅 Current plan</h3>
<b>Name</b>: {{ realm.current_plan.name }}<br /> <b>Name</b>: {{ plan_data[realm.id].current_plan.name }}<br />
<b>Status</b>: {{realm.current_plan.get_plan_status_as_text()}}<br /> <b>Status</b>: {{plan_data[realm.id].current_plan.get_plan_status_as_text()}}<br />
<b>Billing schedule</b>: {% if realm.current_plan.billing_schedule == realm.current_plan.ANNUAL %}Annual{% else %}Monthly{% endif %}<br /> <b>Billing schedule</b>: {% if plan_data[realm.id].current_plan.billing_schedule == plan_data[realm.id].current_plan.ANNUAL %}Annual{% else %}Monthly{% endif %}<br />
<b>Licenses</b>: {{ realm.current_plan.licenses_used }}/{{ realm.current_plan.licenses }} ({% if realm.current_plan.automanage_licenses %}Automatic{% else %}Manual{% endif %})<br /> <b>Licenses</b>: {{ plan_data[realm.id].licenses_used }}/{{ plan_data[realm.id].licenses }} ({% if plan_data[realm.id].current_plan.automanage_licenses %}Automatic{% else %}Manual{% endif %})<br />
{% if realm.current_plan.price_per_license %} {% if plan_data[realm.id].current_plan.price_per_license %}
<b>Price per license</b>: ${{ realm.current_plan.price_per_license/100 }}<br /> <b>Price per license</b>: ${{ plan_data[realm.id].current_plan.price_per_license/100 }}<br />
{% else %} {% else %}
<b>Fixed price</b>: ${{ realm.current_plan.fixed_price/100 }}<br /> <b>Fixed price</b>: ${{ plan_data[realm.id].current_plan.fixed_price/100 }}<br />
{% endif %} {% endif %}
<b>Next invoice date</b>: {{ realm.current_plan.next_invoice_date.strftime('%d %B %Y') }}<br /> <b>Next invoice date</b>: {{ plan_data[realm.id].current_plan.next_invoice_date.strftime('%d %B %Y') }}<br />
</div> </div>
<form method="POST" class="billing-method-form"> <form method="POST" class="billing-method-form">
@@ -131,8 +131,8 @@
{{ csrf_input }} {{ csrf_input }}
<input type="hidden" name="realm_id" value="{{ realm.id }}" /> <input type="hidden" name="realm_id" value="{{ realm.id }}" />
<select name="billing_method" class="billing-method-select" required> <select name="billing_method" class="billing-method-select" required>
<option value="charge_automatically" {% if realm.current_plan.charge_automatically %}selected{% endif %}>Charge automatically</option> <option value="charge_automatically" {% if plan_data[realm.id].current_plan.charge_automatically %}selected{% endif %}>Charge automatically</option>
<option value="send_invoice" {% if not realm.current_plan.charge_automatically %}selected{% endif %}>Pay by invoice</option> <option value="send_invoice" {% if not plan_data[realm.id].current_plan.charge_automatically %}selected{% endif %}>Pay by invoice</option>
</select> </select>
<button type="submit" class="btn btn-default support-submit-button">Update</button> <button type="submit" class="btn btn-default support-submit-button">Update</button>
</form> </form>