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

1# Copyright © Michal Čihař <michal@weblate.org> 

2# 

3# SPDX-License-Identifier: GPL-3.0-or-later 

4 

5from __future__ import annotations 

6 

7from typing import TYPE_CHECKING 

8 

9from django.contrib import admin 

10from django.contrib.admin import RelatedOnlyFieldListFilter 

11from django.utils.translation import gettext_lazy 

12 

13from weblate.wladmin.models import WeblateModelAdmin 

14 

15from .models import Billing, Invoice, Plan 

16 

17if TYPE_CHECKING: 

18 from weblate.auth.models import AuthenticatedHttpRequest 

19 

20 

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") 

42 

43 

44def format_user(obj) -> str: 

45 return f"{obj.username}: {obj.full_name} <{obj.email}>" 

46 

47 

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") 

72 

73 def get_queryset(self, request: AuthenticatedHttpRequest): 

74 return super().get_queryset(request).prefetch_related("projects", "owners") 

75 

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) 

81 

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()) 

85 

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 

90 

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) 

102 

103 

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",)