diff --git a/fet2020/finance/admin.py b/fet2020/finance/admin.py index 1bd89874..007b7e11 100644 --- a/fet2020/finance/admin.py +++ b/fet2020/finance/admin.py @@ -2,8 +2,25 @@ from django.contrib import admin, messages from django.utils.safestring import mark_safe from django.utils.translation import ngettext -from .forms import BankDataAdminForm, BillAdminForm, ResolutionAdminForm -from .models import BankData, Bill, Resolution +from .forms import ( + BankDataAdminForm, + BillAdminForm, + BillInlineForm, + ResolutionAdminForm, + WirefAdminForm, +) +from .models import BankData, Bill, Resolution, Wiref + + +class BillInline(admin.TabularInline): + form = BillInlineForm + model = Bill + + can_delete = False + extra = 0 + max_num = 0 + readonly_fields = ("purpose", "amount", "file_field") + show_change_link = True class BankDataAdmin(admin.ModelAdmin): @@ -15,6 +32,25 @@ class BankDataAdmin(admin.ModelAdmin): "iban", ] + def add_view(self, request, form_url="", extra_context=None): + extra_context = extra_context or {} + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." + return super().add_view( + request, + form_url, + extra_context=extra_context, + ) + + def change_view(self, request, object_id, form_url="", extra_context=None): + extra_context = extra_context or {} + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." + return super().change_view( + request, + object_id, + form_url, + extra_context=extra_context, + ) + class BillAdmin(admin.ModelAdmin): form = BillAdminForm @@ -29,13 +65,12 @@ class BillAdmin(admin.ModelAdmin): "status_colored", "bill_creator", "affiliation", - "wiref_id", ] actions = ["make_cleared", "make_finished"] list_filter = ["status", "affiliation"] - search_fields = ["wiref_id", "purpose"] ordering = ["date_created"] + search_fields = ["purpose"] readonly_fields = ["get_bankdata_name", "get_bankdata_iban", "get_bankdata_bic"] fieldsets = ( @@ -77,7 +112,7 @@ class BillAdmin(admin.ModelAdmin): { "fields": ( "comment", - "wiref_id", + "wiref", "status", ) }, @@ -139,11 +174,13 @@ class BillAdmin(admin.ModelAdmin): def status_colored(self, obj): colors = { - 'S': 'red', - 'C': 'darkorange', - 'F': 'green', + "S": "red", + "C": "darkorange", + "F": "green", } - return mark_safe('{}'.format(colors[obj.status], obj.get_status_display())) + return mark_safe( + f'{obj.get_status_display()}' + ) status_colored.short_description = "Status" @@ -180,13 +217,88 @@ class ResolutionAdmin(admin.ModelAdmin): form = ResolutionAdminForm model = Resolution + inlines = (BillInline,) + list_display = [ "name", "id", "is_visible", + "total", ] + def add_view(self, request, form_url="", extra_context=None): + extra_context = extra_context or {} + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." + return super().add_view( + request, + form_url, + extra_context=extra_context, + ) + + def change_view(self, request, object_id, form_url="", extra_context=None): + extra_context = extra_context or {} + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." + return super().change_view( + request, + object_id, + form_url, + extra_context=extra_context, + ) + + def total(self, obj): + total = 0 + bills = Bill.objects.filter(resolution=obj) + for elem in bills: + total += elem.amount + + return f"{ total }" + + total.short_description = "Gesamtsumme (EUR)" + + +class WirefAdmin(admin.ModelAdmin): + form = WirefAdminForm + model = Wiref + + inlines = (BillInline,) + + list_display = [ + "wiref_id", + "file_field", + "total", + ] + + def add_view(self, request, form_url="", extra_context=None): + extra_context = extra_context or {} + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." + return super().add_view( + request, + form_url, + extra_context=extra_context, + ) + + def change_view(self, request, object_id, form_url="", extra_context=None): + extra_context = extra_context or {} + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." + return super().change_view( + request, + object_id, + form_url, + extra_context=extra_context, + ) + + def total(self, obj): + total = 0 + bills = Bill.objects.filter(wiref=obj) + for elem in bills: + total += elem.amount + + return f"{ total }" + + total.short_description = "Gesamtsumme (EUR)" + admin.site.register(BankData, BankDataAdmin) admin.site.register(Bill, BillAdmin) admin.site.register(Resolution, ResolutionAdmin) +admin.site.register(Wiref, WirefAdmin) diff --git a/fet2020/finance/forms.py b/fet2020/finance/forms.py index 1054dabf..c146b333 100644 --- a/fet2020/finance/forms.py +++ b/fet2020/finance/forms.py @@ -4,7 +4,7 @@ from django.forms import DateInput from members.models import Member -from .models import BankData, Bill, Resolution +from .models import BankData, Bill, Resolution, Wiref class DateInput(DateInput): @@ -212,6 +212,20 @@ class BillUpdateForm(forms.ModelForm): self.fields["comment"].disabled = True +class BillInlineForm(forms.ModelForm): + class Meta: + fields = [ + "purpose", + "file_field", + ] + model = Bill + + labels = { + "purpose": "Verwendungszweck", + "file_field": "Hochgeladene Rechnung", + } + + class BankDataAdminForm(forms.ModelForm): class Meta: model = BankData @@ -258,7 +272,62 @@ class BillAdminForm(forms.ModelForm): class ResolutionAdminForm(forms.ModelForm): + total = forms.CharField() + class Meta: model = Resolution - fields = "__all__" + fields = [ + "name", + "id", + "is_visible", + "total", + ] + + labels = { + "id": "ID", + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # to get the self.fields set + + bills = Bill.objects.filter(resolution=kwargs["instance"]) + total = 0 + for elem in bills: + total += elem.amount + + self.fields["total"].disabled = True + self.fields["total"].initial = total + self.fields["total"].label = "Gesamtsumme (EUR)" + self.fields["total"].required = False + + +class WirefAdminForm(forms.ModelForm): + total = forms.CharField() + + class Meta: + model = Wiref + + fields = [ + "wiref_id", + "file_field", + "total", + ] + + labels = { + "wiref_id": "Wiref ID", + "file_field": "Wiref Formular", + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # to get the self.fields set + + bills = Bill.objects.filter(wiref=kwargs["instance"]) + total = 0 + for elem in bills: + total += elem.amount + + self.fields["total"].disabled = True + self.fields["total"].initial = total + self.fields["total"].label = "Gesamtsumme (EUR)" + self.fields["total"].required = False diff --git a/fet2020/finance/models.py b/fet2020/finance/models.py index dbd87637..1f05f39c 100644 --- a/fet2020/finance/models.py +++ b/fet2020/finance/models.py @@ -40,6 +40,25 @@ class Resolution(models.Model): return f"{self.name}" +class Wiref(models.Model): + wiref_id = models.CharField(max_length=10, blank=True, null=True) + + file_field = models.FileField( + upload_to="uploads/finance/wiref/", + validators=[FileExtensionValidator(["pdf"])], + blank=True, + null=True, + verbose_name="Wiref Formular", + ) + + class Meta: + verbose_name = "Wiref Formular" + verbose_name_plural = "Wiref Formulare" + + def __str__(self): + return f"{self.wiref_id}" + + class Bill(models.Model): # members can be deleted but never their bills bill_creator = models.ForeignKey( @@ -86,7 +105,7 @@ class Bill(models.Model): only_digital = models.BooleanField(default=False, verbose_name="Digitale Rechnung") file_field = models.FileField( - upload_to="uploads/finance/files/", + upload_to="uploads/finance/bills/", validators=[FileExtensionValidator(["pdf"])], blank=True, null=True, @@ -105,7 +124,14 @@ class Bill(models.Model): default=Status.SUBMITTED, verbose_name="Status", ) - wiref_id = models.CharField(max_length=10, blank=True, null=True) + + wiref = models.ForeignKey( + Wiref, + on_delete=models.SET_NULL, + blank=True, + null=True, + verbose_name="Wiref", + ) date_created = models.DateTimeField(auto_now_add=True)