diff --git a/fet2020/fet2020/settings.py b/fet2020/fet2020/settings.py index 014953d6..dce58856 100644 --- a/fet2020/fet2020/settings.py +++ b/fet2020/fet2020/settings.py @@ -59,6 +59,7 @@ INSTALLED_APPS = [ "tasks.apps.TasksConfig", "gallery.apps.GalleryConfig", "intern.apps.InternConfig", + "finance.apps.FinanceConfig", ] diff --git a/fet2020/fet2020/urls.py b/fet2020/fet2020/urls.py index cde5b265..ea72e004 100644 --- a/fet2020/fet2020/urls.py +++ b/fet2020/fet2020/urls.py @@ -33,6 +33,7 @@ urlpatterns = [ path("auth/", include("authentications.urls")), path("api/", include(router.urls)), path("ckeditor/", include("ckeditor_uploader.urls")), + path("finance/", include("finance.urls")), path("gallery/", include("gallery.urls")), path("intern/", include("intern.urls")), path("jobs/", include("blackboard.urls")), diff --git a/fet2020/finance/__init__.py b/fet2020/finance/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fet2020/finance/admin.py b/fet2020/finance/admin.py new file mode 100644 index 00000000..d3840f4a --- /dev/null +++ b/fet2020/finance/admin.py @@ -0,0 +1,183 @@ +from django.contrib import admin + +from .forms import BankDataAdminForm, BillAdminForm, ResolutionAdminForm +from .models import BankData, Bill, Resolution + +from django.contrib import messages +from django.utils.translation import ngettext + + +class BankDataAdmin(admin.ModelAdmin): + form = BankDataAdminForm + model = BankData + + list_display = [ + "name", + "iban", + ] + + +class BillAdmin(admin.ModelAdmin): + form = BillAdminForm + model = Bill + + list_display = [ + "id", + "only_digital", + "amount", + "purpose", + "resolution", + "status", + "bill_creator", + "affiliation", + "wiref_id", + ] + + actions = ["make_cleared", "make_finished"] + list_filter = ["status", "affiliation"] + search_fields = ["wiref_id", "purpose"] + ordering = ["date_created"] + + readonly_fields = ["get_bankdata_name", "get_bankdata_iban", "get_bankdata_bic"] + fieldsets = ( + ( + None, + { + "fields": ( + "bill_creator", + "resolution", + ) + }, + ), + ( + "Bankdaten", + { + "fields": ( + "payer", + "bankdata", + ("get_bankdata_name", "get_bankdata_iban", "get_bankdata_bic"), + ) + }, + ), + ( + "Rechnung", + { + "fields": ( + "affiliation", + "date", + "invoice", + "purpose", + "amount", + "only_digital", + "file_field", + ) + }, + ), + ( + "Sonstiges", + { + "fields": ( + "comment", + "wiref_id", + "status", + ) + }, + ), + ) + + 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 save_model(self, request, obj, form, change): + obj.author = request.user + super().save_model(request, obj, form, change) + + def get_bankdata_name(self, obj): + try: + tmp = BankData.objects.get(id=obj.bankdata.id) + except Exception: + return "-" + + return f"{ tmp.name }" + + get_bankdata_name.short_description = "Kontoinhaber:in" + + def get_bankdata_iban(self, obj): + try: + tmp = BankData.objects.get(id=obj.bankdata.id) + except Exception: + return "-" + + return f"{ tmp.iban }" + + get_bankdata_iban.short_description = "IBAN" + + def get_bankdata_bic(self, obj): + try: + tmp = BankData.objects.get(id=obj.bankdata.id) + except Exception: + return "-" + + return f"{ tmp.bic }" + + get_bankdata_bic.short_description = "BIC" + + @admin.action(description="Als 'Abgerechnet' markieren.") + def make_cleared(self, request, queryset): + updated = queryset.update(status="C") + self.message_user( + request, + ngettext( + "%d Rechnung wurde als 'Abgerechnet' markiert.", + "%d Rechnungen wurde als 'Abgerechnet' markiert.", + updated, + ) + % updated, + messages.SUCCESS, + ) + + @admin.action(description="Als 'Abgeschlossen' markieren.") + def make_finished(self, request, queryset): + updated = queryset.update(status="F") + self.message_user( + request, + ngettext( + "%d Rechnung wurde als 'Abgeschlossen' markiert.", + "%d Rechnungen wurde als 'Abgeschlossen' markiert.", + updated, + ) + % updated, + messages.SUCCESS, + ) + + +class ResolutionAdmin(admin.ModelAdmin): + form = ResolutionAdminForm + model = Resolution + + list_display = [ + "name", + "id", + "is_visible", + ] + + +admin.site.register(BankData, BankDataAdmin) +admin.site.register(Bill, BillAdmin) +admin.site.register(Resolution, ResolutionAdmin) diff --git a/fet2020/finance/apps.py b/fet2020/finance/apps.py new file mode 100644 index 00000000..874f45fa --- /dev/null +++ b/fet2020/finance/apps.py @@ -0,0 +1,12 @@ +from django.apps import AppConfig +from django.db.models.signals import post_migrate + +from fet2020.utils import create_perms + + +class FinanceConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "finance" + + def ready(self): + post_migrate.connect(create_perms, sender=self) diff --git a/fet2020/finance/forms.py b/fet2020/finance/forms.py new file mode 100644 index 00000000..1054dabf --- /dev/null +++ b/fet2020/finance/forms.py @@ -0,0 +1,264 @@ +from django import forms +from django.core.validators import ValidationError +from django.forms import DateInput + +from members.models import Member + +from .models import BankData, Bill, Resolution + + +class DateInput(DateInput): + input_type = "date" + + +class BankDataForm(forms.ModelForm): + class Meta: + model = BankData + + fields = ["iban", "bic", "name"] + + labels = {"iban": "IBAN", "bic": "BIC", "name": "Kontoinhaber:in"} + + +class BillCreateForm(forms.ModelForm): + resolution_text = forms.CharField(max_length=128) + name_text = forms.CharField(max_length=128) + iban_text = forms.CharField(max_length=34) + bic_text = forms.CharField(max_length=11) + + class Meta: + model = Bill + + fields = [ + "bill_creator", + "date", + "invoice", + "amount", + "purpose", + "affiliation", + "payer", + "only_digital", + "file_field", + "comment", + "resolution", + ] + + labels = { + "bill_creator": "Verantwortliche:r für die Einreichung", + "date": "Rechnungsdatum", + "invoice": "Rechnungsaussteller", + "amount": "Betrag (EUR)", + "purpose": "Verwendungszweck", + "affiliation": "Abrechnungsbudget", + "payer": "Wie wurde die Rechnung bezahlt?", + "only_digital": "Ich habe nur eine digitale Rechnung.", + "file_field": "Rechnung hochladen (PDF)", + "comment": "Kommentar", + } + + widgets = { + "date": DateInput(format=("%Y-%m-%d")), + } + + def __init__(self, *args, **kwargs): + if "user" in kwargs: + user = kwargs.pop("user") + else: + user = None + + super().__init__(*args, **kwargs) # to get the self.fields set + + self.fields["bill_creator"].initial = Member.objects.get(username=user.username) + self.fields["bill_creator"].disabled = True + + self.fields["invoice"].placeholder = "Firmenname\nStraße\nPLZ Ort" + self.fields["invoice"].rows = 3 + + # bank data fields + self.fields["name_text"].label = "Kontoinhaber:in" + self.fields["name_text"].required = False + + self.fields["iban_text"].label = "IBAN" + self.fields["iban_text"].required = False + + self.fields["bic_text"].label = "BIC" + self.fields["bic_text"].required = False + + # resolution fields + self.fields["resolution_text"].label = "Beschlussnummer" + self.fields["resolution_text"].required = False + + def clean(self): + cleaned_data = super().clean() + + amount = cleaned_data.get("amount") + resolution = cleaned_data.get("resolution_text") + + payer = cleaned_data.get("payer") + name = cleaned_data.get("name_text") + iban = cleaned_data.get("iban_text") + bic = cleaned_data.get("bic_text") + + only_digital = cleaned_data.get("only_digital") + file_field = cleaned_data.get("file_field") + + # check that amount is valid because invalid amount is a NoneType. + if amount: + if amount > 30 and resolution == "": + raise ValidationError( + "Die Beschlussnummer fehlt, weil der Betrag über 30€ beträgt " + f"(Betrag: {amount}€)." + ) + + if payer == "M": + if name == "" or iban == "": + raise ValidationError( + f"Bankdaten unvollständig (Kontoinhaber: {name}, IBAN: {iban})." + ) + + if payer == "V": + cleaned_data["name_text"] = "" + cleaned_data["iban_text"] = "" + cleaned_data["bic_text"] = "" + + if only_digital and file_field is None: + raise ValidationError(f"Digitale Rechnung fehlt.") + + return cleaned_data + + +class BillUpdateForm(forms.ModelForm): + resolution_text = forms.CharField(max_length=128) + name_text = forms.CharField(max_length=128) + iban_text = forms.CharField(max_length=34) + bic_text = forms.CharField(max_length=11) + + class Meta: + model = Bill + + fields = [ + "bill_creator", + "date", + "invoice", + "amount", + "purpose", + "affiliation", + "payer", + "only_digital", + "file_field", + "comment", + "resolution", + ] + + labels = { + "bill_creator": "Verantwortliche:r für die Einreichung", + "date": "Rechnungsdatum", + "invoice": "Rechnungsaussteller", + "amount": "Betrag (EUR)", + "purpose": "Verwendungszweck", + "affiliation": "Abrechnungsbudget", + "payer": "Wie wurde die Rechnung bezahlt?", + "only_digital": "Ich habe nur eine digitale Rechnung.", + "file_field": "Rechnung hochladen (PDF)", + "comment": "Kommentar", + } + + widgets = { + "date": DateInput(format=("%Y-%m-%d")), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # to get the self.fields set + + self.fields["bill_creator"].disabled = True + self.fields["date"].disabled = True + self.fields["invoice"].disabled = True + self.fields["amount"].disabled = True + self.fields["purpose"].disabled = True + self.fields["affiliation"].disabled = True + self.fields["payer"].disabled = True + self.fields["only_digital"].disabled = True + self.fields["file_field"].disabled = True + self.fields["resolution"].disabled = True + + # bank data fields + if kwargs["instance"].bankdata: + self.fields["name_text"].initial = kwargs["instance"].bankdata.name + self.fields["iban_text"].initial = kwargs["instance"].bankdata.iban + self.fields["bic_text"].initial = kwargs["instance"].bankdata.bic + + self.fields["name_text"].disabled = True + self.fields["name_text"].label = "Kontoinhaber:in" + self.fields["name_text"].required = False + + self.fields["iban_text"].disabled = True + self.fields["iban_text"].label = "IBAN" + self.fields["iban_text"].required = False + + self.fields["bic_text"].disabled = True + self.fields["bic_text"].label = "BIC" + self.fields["bic_text"].required = False + + # resolution fields + if kwargs["instance"].resolution: + self.fields["resolution_text"].initial = kwargs["instance"].resolution.name + + self.fields["resolution_text"].disabled = True + self.fields["resolution_text"].label = "Beschlussnummer" + self.fields["resolution_text"].required = False + + # comment disabled when bill is cleared or finished + if kwargs["instance"].status != "S": + self.fields["comment"].disabled = True + + +class BankDataAdminForm(forms.ModelForm): + class Meta: + model = BankData + + fields = "__all__" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # to get the self.fields set + + self.fields["bankdata_creator"].widget.can_add_related = False + self.fields["bankdata_creator"].widget.can_change_related = False + self.fields["bankdata_creator"].widget.can_delete_related = False + + +class BillAdminForm(forms.ModelForm): + class Meta: + model = Bill + + fields = "__all__" + + labels = { + "affiliation": "Abrechnungsbudget", + "amount": "Betrag (EUR)", + "comment": "Kommentar", + "date": "Rechnungsdatum", + "file_field": "Rechnung hochladen (PDF)", + "invoice": "Rechnungsaussteller", + "only_digital": "Ich habe nur eine digitale Rechnung.", + "payer": "Wie wurde die Rechnung bezahlt?", + "purpose": "Verwendungszweck", + "resolution": "Beschlussnummer", + } + + widgets = { + "date": DateInput(format=("%Y-%m-%d")), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # to get the self.fields set + + self.fields["bill_creator"].widget.can_add_related = False + self.fields["bill_creator"].widget.can_change_related = False + self.fields["bill_creator"].widget.can_delete_related = False + + +class ResolutionAdminForm(forms.ModelForm): + class Meta: + model = Resolution + + fields = "__all__" diff --git a/fet2020/finance/migrations/0001_initial.py b/fet2020/finance/migrations/0001_initial.py new file mode 100644 index 00000000..a6e0cc26 --- /dev/null +++ b/fet2020/finance/migrations/0001_initial.py @@ -0,0 +1,178 @@ +# Generated by Django 4.2.2 on 2023-08-22 16:57 + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("members", "0007_alter_member_username"), + ] + + operations = [ + migrations.CreateModel( + name="BankData", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField(max_length=128, verbose_name="Kontoinhaber:in"), + ), + ("iban", models.CharField(max_length=34, verbose_name="IBAN")), + ("bic", models.CharField(max_length=11, verbose_name="BIC")), + ( + "is_disabled", + models.BooleanField(default=False, verbose_name="deaktiviert"), + ), + ( + "bankdata_creator", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="members.member", + verbose_name="Verknüpfung zum Mitglied", + ), + ), + ], + options={ + "verbose_name": "Bankdaten", + "verbose_name_plural": "Bankdaten", + }, + ), + migrations.CreateModel( + name="Resolution", + fields=[ + ( + "id", + models.CharField(max_length=128, primary_key=True, serialize=False), + ), + ("name", models.CharField(max_length=128)), + ( + "is_visible", + models.BooleanField(default=False, verbose_name="sichtbar"), + ), + ], + options={ + "verbose_name": "Beschluss", + "verbose_name_plural": "Beschlüsse", + }, + ), + migrations.CreateModel( + name="Bill", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("date", models.DateField()), + ("invoice", models.TextField()), + ( + "amount", + models.DecimalField( + decimal_places=2, max_digits=7, verbose_name="Betrag (EUR)" + ), + ), + ( + "purpose", + models.CharField(max_length=140, verbose_name="Verwendungszweck"), + ), + ( + "affiliation", + models.CharField( + choices=[("V", "Vereinsbudget"), ("B", "Offizielles Budget")], + max_length=1, + verbose_name="Abrechnungsbudget", + ), + ), + ( + "payer", + models.CharField( + choices=[("M", "Privat"), ("V", "Verein (Safe/Kreditkarte)")], + max_length=1, + ), + ), + ( + "only_digital", + models.BooleanField( + default=False, verbose_name="Digitale Rechnung" + ), + ), + ( + "file_field", + models.FileField( + blank=True, + null=True, + upload_to="uploads/finance/files/", + validators=[ + django.core.validators.FileExtensionValidator(["pdf"]) + ], + ), + ), + ("comment", models.TextField(blank=True, null=True)), + ( + "status", + models.CharField( + choices=[ + ("S", "Eingereicht"), + ("C", "Abgerechnet"), + ("F", "Abgeschlossen"), + ], + default="S", + max_length=1, + verbose_name="Status", + ), + ), + ("wiref_id", models.CharField(blank=True, max_length=10, null=True)), + ("date_created", models.DateTimeField(auto_now_add=True)), + ( + "bankdata", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="finance.bankdata", + verbose_name="Kontodaten", + ), + ), + ( + "bill_creator", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="members.member", + verbose_name="Verantwortliche:r", + ), + ), + ( + "resolution", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="finance.resolution", + verbose_name="Beschlussnummer", + ), + ), + ], + options={ + "verbose_name": "Rechnung", + "verbose_name_plural": "Rechnungen", + }, + ), + ] diff --git a/fet2020/finance/migrations/__init__.py b/fet2020/finance/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fet2020/finance/models.py b/fet2020/finance/models.py new file mode 100644 index 00000000..dbd87637 --- /dev/null +++ b/fet2020/finance/models.py @@ -0,0 +1,121 @@ +from django.core.validators import FileExtensionValidator, ValidationError +from django.db import models + +from members.models import Member + + +class BankData(models.Model): + # members can be deleted but never their bank datas + bankdata_creator = models.ForeignKey( + Member, + on_delete=models.SET_NULL, + null=True, + verbose_name="Verknüpfung zum Mitglied", + ) + name = models.CharField(max_length=128, verbose_name="Kontoinhaber:in") + iban = models.CharField(max_length=34, verbose_name="IBAN") + bic = models.CharField(max_length=11, verbose_name="BIC") + + is_disabled = models.BooleanField(default=False, verbose_name="deaktiviert") + + class Meta: + verbose_name = "Bankdaten" + verbose_name_plural = "Bankdaten" + + def __str__(self): + return f"{self.name} - {self.iban}" + + +class Resolution(models.Model): + id = models.CharField(primary_key=True, max_length=128) + name = models.CharField(max_length=128) + + is_visible = models.BooleanField(default=False, verbose_name="sichtbar") + + class Meta: + verbose_name = "Beschluss" + verbose_name_plural = "Beschlüsse" + + def __str__(self): + return f"{self.name}" + + +class Bill(models.Model): + # members can be deleted but never their bills + bill_creator = models.ForeignKey( + Member, on_delete=models.PROTECT, verbose_name="Verantwortliche:r" + ) + + bankdata = models.ForeignKey( + BankData, + on_delete=models.SET_NULL, + blank=True, + null=True, + verbose_name="Kontodaten", + ) + + resolution = models.ForeignKey( + Resolution, + on_delete=models.SET_NULL, + blank=True, + null=True, + verbose_name="Beschlussnummer", + ) + + date = models.DateField() + invoice = models.TextField() + amount = models.DecimalField( + max_digits=7, decimal_places=2, verbose_name="Betrag (EUR)" + ) + purpose = models.CharField(max_length=140, verbose_name="Verwendungszweck") + + class Affiliation(models.TextChoices): + VEREIN = "V", "Vereinsbudget" + OFFICIAL = "B", "Offizielles Budget" + + affiliation = models.CharField( + max_length=1, choices=Affiliation.choices, verbose_name="Abrechnungsbudget" + ) + + class Payer(models.TextChoices): + ME = "M", "Privat" + VEREIN = "V", "Verein (Safe/Kreditkarte)" + + payer = models.CharField(max_length=1, choices=Payer.choices) + + only_digital = models.BooleanField(default=False, verbose_name="Digitale Rechnung") + + file_field = models.FileField( + upload_to="uploads/finance/files/", + validators=[FileExtensionValidator(["pdf"])], + blank=True, + null=True, + ) + + comment = models.TextField(blank=True, null=True) + + class Status(models.TextChoices): + SUBMITTED = "S", "Eingereicht" + CLEARED = "C", "Abgerechnet" + FINISHED = "F", "Abgeschlossen" + + status = models.CharField( + max_length=1, + choices=Status.choices, + default=Status.SUBMITTED, + verbose_name="Status", + ) + wiref_id = models.CharField(max_length=10, blank=True, null=True) + + date_created = models.DateTimeField(auto_now_add=True) + + class Meta: + verbose_name = "Rechnung" + verbose_name_plural = "Rechnungen" + + def __str__(self): + return f"{self.purpose}" + + def clean(self): + if self.status is None: + self.status = Bill.Status.SUBMITTED diff --git a/fet2020/finance/tests.py b/fet2020/finance/tests.py new file mode 100644 index 00000000..e69de29b diff --git a/fet2020/finance/urls.py b/fet2020/finance/urls.py new file mode 100644 index 00000000..dd643448 --- /dev/null +++ b/fet2020/finance/urls.py @@ -0,0 +1,16 @@ +from django.urls import path + +from . import apps, views +from .views import ( + BillCreateView, + BillListView, + BillUpdateView, +) + +app_name = apps.FinanceConfig.name + +urlpatterns = [ + path("", BillListView.as_view(), name="bill_list"), + path("/", BillUpdateView.as_view(), name="bill_update"), + path("create-bill/", BillCreateView.as_view(), name="bill_create"), +] diff --git a/fet2020/finance/views.py b/fet2020/finance/views.py new file mode 100644 index 00000000..7fb3b19e --- /dev/null +++ b/fet2020/finance/views.py @@ -0,0 +1,80 @@ +from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin +from django.contrib.auth.models import User +from django.shortcuts import redirect +from django.urls import reverse_lazy +from django.views.generic import ListView +from django.views.generic.detail import DetailView +from django.views.generic.edit import CreateView, UpdateView + +from fet2020.utils import add_log_action, create_formsets +from members.models import Member + +from .forms import BankDataForm, BillCreateForm, BillUpdateForm +from .models import Bill, BankData, Resolution + + +class BillCreateView(LoginRequiredMixin, CreateView): + form_class = BillCreateForm + model = Bill + success_url = reverse_lazy("finance:bill_list") + template_name = "finance/bill_create.html" + + def form_valid(self, form): + # get or create resolution object + resolution = form.cleaned_data["resolution_text"] + if resolution != "": + obj, created = Resolution.objects.get_or_create( + id=resolution, defaults={"name": resolution} + ) + form.instance.resolution = obj + + # get or create bankdata object + name = form.cleaned_data["name_text"] + iban = form.cleaned_data["iban_text"] + bic = form.cleaned_data["bic_text"] + if name != "" and iban != "" and bic != "": + obj, created = BankData.objects.get_or_create( + name=name, + iban=iban, + bic=bic, + defaults={"bankdata_creator": form.cleaned_data["bill_creator"]}, + ) + form.instance.bankdata = obj + + add_log_action(self.request, form, "finance", "bill", True) + return super().form_valid(form) + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs["user"] = self.request.user + return kwargs + + +class BillListView(LoginRequiredMixin, ListView): + model = Bill + template_name = "finance/index.html" + + def get_queryset(self): + return Bill.objects.filter(bill_creator__username=self.request.user) + + +class BillUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView): + form_class = BillUpdateForm + model = Bill + success_url = reverse_lazy("finance:bill_list") + template_name = "finance/bill_update.html" + + def form_valid(self, form): + add_log_action(self.request, form, "finance", "bill", False) + return super().form_valid(form) + + # call bill if it's only yours + def test_func(self): + if self.get_object().bill_creator.username == self.request.user.username: + return True + + # call handle_no_permissions method + return False + + def handle_no_permission(self): + return redirect("finance:bill_list") diff --git a/fet2020/templates/baseform/text_with_suggestions.html b/fet2020/templates/baseform/text_with_suggestions.html new file mode 100644 index 00000000..ce974f6b --- /dev/null +++ b/fet2020/templates/baseform/text_with_suggestions.html @@ -0,0 +1,24 @@ + diff --git a/fet2020/templates/finance/bill_create.html b/fet2020/templates/finance/bill_create.html new file mode 100644 index 00000000..2fc9023a --- /dev/null +++ b/fet2020/templates/finance/bill_create.html @@ -0,0 +1,67 @@ +{% extends 'base.html' %} + +{% block title %}Neue Rechnung einreichen{% endblock %} + +{% block content %} + +
+

Neue Rechnung einreichen

+
+
+ {% csrf_token %} + {% include "baseform/non_field_errors.html" %} + + {% include "baseform/select.html" with field=form.bill_creator %} + +
+ Bankdaten + + {% include "baseform/select.html" with field=form.payer %} + {% include "baseform/text_with_suggestions.html" with field=form.name_text %} + {% include "baseform/text.html" with field=form.iban_text %} + {% include "baseform/text.html" with field=form.bic_text %} + +
+ Rechnung + + {% include "baseform/date.html" with field=form.date %} + {% include "baseform/textarea.html" with field=form.invoice %} + {% include "baseform/text.html" with field=form.purpose %} + + + + {% include "baseform/checkbox.html" with field=form.only_digital %} + {% include "baseform/file.html" with field=form.file_field %} + +
+ Beschlusslage + + {% include "baseform/select.html" with field=form.affiliation %} + {% include "baseform/text.html" with field=form.resolution_text %} + +
+ {% include "baseform/textarea.html" with field=form.comment %} + +
+ +
+
+
+
+{% endblock %} diff --git a/fet2020/templates/finance/bill_update.html b/fet2020/templates/finance/bill_update.html new file mode 100644 index 00000000..3a9164b6 --- /dev/null +++ b/fet2020/templates/finance/bill_update.html @@ -0,0 +1,70 @@ +{% extends 'base.html' %} + +{% block title %}Rechnung {{ object.pk }}{% endblock %} + +{% block content %} + +
+

Rechnung {{ object.pk }}

+
+
+ {% csrf_token %} + {% include "baseform/non_field_errors.html" %} + + {% include "baseform/select.html" with field=form.bill_creator %} + +
+ Bankdaten + + {% include "baseform/select.html" with field=form.payer %} + {% if form.name_text.value %} + {% include "baseform/text.html" with field=form.name_text %} + {% endif %} + {% if form.iban_text.value %} + {% include "baseform/text.html" with field=form.iban_text %} + {% endif %} + {% if form.bic_text.value %} + {% include "baseform/text.html" with field=form.bic_text %} + {% endif %} + +
+ Rechnung + + {% include "baseform/text.html" with field=form.date %} + {% include "baseform/textarea.html" with field=form.invoice %} + {% include "baseform/text.html" with field=form.purpose %} + {% include "baseform/text.html" with field=form.amount %} + + {% if form.file_field.value %} + {% include "baseform/checkbox.html" with field=form.only_digital %} + + + {% else %} + Keine digitale Rechnung eingereicht. + {% endif %} + +
+ Beschlusslage + + {% include "baseform/select.html" with field=form.affiliation %} + {% if form.resolution_text.value %} + {% include "baseform/text.html" with field=form.resolution_text %} + {% endif %} + +
+ {% include "baseform/textarea.html" with field=form.comment %} + +
+ +
+
+
+
+{% endblock %} diff --git a/fet2020/templates/finance/index.html b/fet2020/templates/finance/index.html new file mode 100644 index 00000000..e68eae0e --- /dev/null +++ b/fet2020/templates/finance/index.html @@ -0,0 +1,50 @@ +{% extends "base.html" %} + +{% block title %}Übersicht über die Rechnungen{% endblock %} + +{% block content %} + +
+

Übersicht über alle von dir eingereichten Rechnungen

+ +
+ +
+ + {% if not object_list %} +
+
+

Keine Rechnungen für dich in dieser Liste.

+
+
+ {% endif %} + + +
+{% endblock %} diff --git a/fet2020/templates/home.html b/fet2020/templates/home.html index 2451fac1..c59aa371 100644 --- a/fet2020/templates/home.html +++ b/fet2020/templates/home.html @@ -42,6 +42,18 @@ Neue Fachschaftssitzung +
  • + + + Neue Rechnung einreichen + +
  • +
  • + + + Übersicht über alle von dir eingereichten Rechnungen + +