Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show active members in the Organization Admin #704

Merged
merged 13 commits into from
Jul 5, 2023
32 changes: 20 additions & 12 deletions docker-app/qfieldcloud/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1051,14 +1051,13 @@ class OrganizationAdmin(QFieldCloudModelAdmin):
"email",
"organization_owner",
"date_joined",
"active_users_links",
)
list_display = (
"username",
"email",
"organization_owner__link",
"date_joined",
# "storage_usage__field",
"active_users",
)
suricactus marked this conversation as resolved.
Show resolved Hide resolved

search_fields = (
Expand All @@ -1068,22 +1067,31 @@ class OrganizationAdmin(QFieldCloudModelAdmin):
"organization_owner__email__iexact",
)

readonly_fields = ("date_joined", "storage_usage__field", "active_users")
readonly_fields = (
"date_joined",
"storage_usage__field",
"active_users_links",
)

list_select_related = ("organization_owner",)
list_select_related = ("organization_owner", "useraccount")

list_filter = ("date_joined",)

autocomplete_fields = ("organization_owner",)

@admin.display(description=_("Active users (last billing period)"))
def active_users(self, instance) -> int | None:
# The relation 'current_subscription_vw' is not instantiated unless the organization
# does have a current subscription
if hasattr(instance, "current_subscription_vw"):
return instance.current_subscription_vw.active_users_count
else:
return None
faebebin marked this conversation as resolved.
Show resolved Hide resolved
@admin.display(description=_("Active members"))
def active_users_links(self, instance) -> str:
persons = instance.useraccount.current_subscription.active_users
userlinks = "<p> - </p>"
if persons:
userlinks = "<br>".join(model_admin_url(p, p.username) for p in persons)
help_text = """
<p style="font-size: 11px; color: var(--body-quiet-color)">
Active members have triggererd at least one job or uploaded at least one delta in the current billing period.
These are all the users who will be billed -- plan included or additional.
</p>
"""
return format_html(f"{userlinks} {help_text}")

@admin.display(description=_("Owner"))
def organization_owner__link(self, instance):
Expand Down
22 changes: 8 additions & 14 deletions docker-app/qfieldcloud/subscription/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,11 +479,14 @@ class UpdateSubscriptionKwargs(TypedDict):
billing_cycle_anchor_at = models.DateTimeField(null=True, blank=True)

# the timestamp when the current billing period started
# NOTE this field remains currently unused.
# NOTE ignored when checking if subscription is 'current' (see `active_since and `active_until`).
# `current_period_since` and `current_period_until` are both either `None` or `datetime`
current_period_since = models.DateTimeField(null=True, blank=True)

# the timestamp when the current billing period ends
# NOTE ignored for subscription validity checks, but used to calculate the activation date when additional packages change
# NOTE ignored when checking if subscription is 'current' (see `active_since and `active_until`),
# but used to calculate the activation date when additional packages change.
# `current_period_since` and `current_period_until` are both either `None` or `datetime`
suricactus marked this conversation as resolved.
Show resolved Hide resolved
current_period_until = models.DateTimeField(null=True, blank=True)

# admin only notes, not visible to end users
Expand Down Expand Up @@ -579,6 +582,7 @@ def has_current_period(self) -> bool:

@property
def active_users(self):
"Returns the queryset of active users for running stripe billing period or None."
if not self.account.user.is_organization:
return None

Expand All @@ -588,25 +592,15 @@ def active_users(self):
self.current_period_until,
)

assert (
self.current_period_since == self.current_period_until
), "Both current_period _since and _until must be set."

now = timezone.now()
month_ago = now - timedelta(days=28)

return self.account.user.active_users(
month_ago,
now,
)
suricactus marked this conversation as resolved.
Show resolved Hide resolved
return None

@property
def active_users_count(self) -> int:
# if non-organization account, then it is always 1 user
if not self.account.user.is_organization:
return 1

if not self.current_period_since or not self.current_period_until:
if self.active_users is None:
return 0

return self.active_users.count()
Expand Down
Loading