Coverage for app/venv/lib/python3.14/site-packages/weblate/billing/admin.py: 0%
53 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
1# Copyright © Michal Čihař <michal@weblate.org>
2#
3# SPDX-License-Identifier: GPL-3.0-or-later
5from __future__ import annotations
7from typing import TYPE_CHECKING
9from django.contrib import admin
10from django.contrib.admin import RelatedOnlyFieldListFilter
11from django.utils.translation import gettext_lazy
13from weblate.wladmin.models import WeblateModelAdmin
15from .models import Billing, Invoice, Plan
17if TYPE_CHECKING:
18 from weblate.auth.models import AuthenticatedHttpRequest
21@admin.register(Plan)
22class PlanAdmin(WeblateModelAdmin):
23 list_display = (
24 "name",
25 "price",
26 "limit_hosted_strings",
27 "limit_strings",
28 "limit_languages",
29 "limit_projects",
30 "display_limit_hosted_strings",
31 "display_limit_strings",
32 "display_limit_languages",
33 "display_limit_projects",
34 "public",
35 "change_access_control",
36 )
37 ordering = ("name",)
38 prepopulated_fields = { # noqa: RUF012
39 "slug": ("name",),
40 }
41 list_filter = ("public", "change_access_control")
44def format_user(obj) -> str:
45 return f"{obj.username}: {obj.full_name} <{obj.email}>"
48@admin.register(Billing)
49class BillingAdmin(WeblateModelAdmin):
50 list_display = (
51 "list_projects",
52 "list_owners",
53 "plan",
54 "state",
55 "removal",
56 "expiry",
57 "monthly_changes",
58 "total_changes",
59 "unit_count",
60 "display_projects",
61 "display_strings",
62 "display_words",
63 "display_languages",
64 "in_limits",
65 "in_display_limits",
66 "paid",
67 "last_invoice",
68 )
69 list_filter = ("plan", "state", "paid", "in_limits")
70 search_fields = ("projects__name", "owners__email")
71 autocomplete_fields = ("projects", "owners")
73 def get_queryset(self, request: AuthenticatedHttpRequest):
74 return super().get_queryset(request).prefetch_related("projects", "owners")
76 @admin.display(description=gettext_lazy("Projects"))
77 def list_projects(self, obj):
78 if not obj.all_projects:
79 return "none projects associated"
80 return ",".join(project.name for project in obj.all_projects)
82 @admin.display(description=gettext_lazy("Owners"))
83 def list_owners(self, obj):
84 return ",".join(owner.full_name for owner in obj.owners.all())
86 def get_form(self, request: AuthenticatedHttpRequest, obj=None, **kwargs):
87 form = super().get_form(request, obj, **kwargs)
88 form.base_fields["owners"].label_from_instance = format_user
89 return form
91 def save_related(
92 self, request: AuthenticatedHttpRequest, form, formsets, change
93 ) -> None:
94 super().save_related(request, form, formsets, change)
95 obj = form.instance
96 # Add owners as admin if there is none
97 for project in obj.projects.all():
98 group = project.defined_groups.get(name="Administration")
99 if not group.user_set.exists():
100 for user in obj.owners.all():
101 user.add_team(request, group)
104@admin.register(Invoice)
105class InvoiceAdmin(WeblateModelAdmin):
106 list_display = ("billing", "start", "end", "amount", "currency", "ref")
107 list_filter = (
108 "currency",
109 ("billing__projects", RelatedOnlyFieldListFilter),
110 ("billing__owners", RelatedOnlyFieldListFilter),
111 )
112 search_fields = ("billing__projects__name", "ref", "note")
113 date_hierarchy = "end"
114 ordering = ("billing", "-start")
115 autocomplete_fields = ("billing",)