Files
fet2020/fet2020/finance/forms.py

513 lines
16 KiB
Python

import decimal
from dateutil.relativedelta import relativedelta
from django import forms
from django.core.exceptions import ValidationError
from django.db.models import Count, Q
from django.forms import DateInput
from django.utils import timezone
from members.models import Member
from .models import BankData, Bill, Resolution, Wiref
class DateInput(DateInput):
input_type = "date"
class BankDataForm(forms.ModelForm):
class Meta:
model = BankData
fields = ["iban", "bic", "name", "address"]
labels = {"iban": "IBAN", "bic": "BIC", "name": "Kontoinhaber:in", "address": "Adresse"}
def get_cleaned_data(cleaned_data):
resolution = cleaned_data.get("resolution_text")
payer = cleaned_data.get("payer")
# Check if resolution exists.
if resolution != "":
try:
cleaned_data["resolution"] = Resolution.objects.get(
Q(id=resolution) | Q(name=resolution),
)
except Exception as exc:
raise ValidationError(
{"resolution_text": "Es gibt keinen Beschluss mit dieser ID."}
) from exc
# If payer is 'Me', you need name, iban and bic data.
if payer == Bill.Payer.ME:
if cleaned_data.get("name_text") == "":
raise ValidationError({"name_text": "Kontoinhaber:in fehlt bei privater Bezahlung."})
if cleaned_data.get("iban_text") == "":
raise ValidationError({"iban_text": "IBAN fehlt bei privater Bezahlung."})
if cleaned_data.get("bic_text") == "":
raise ValidationError({"bic_text": "BIC fehlt bei privater Bezahlung."})
# No saving if payer is 'Verein'.
if payer == Bill.Payer.VEREIN:
cleaned_data["name_text"] = ""
cleaned_data["iban_text"] = ""
cleaned_data["bic_text"] = ""
if cleaned_data.get("only_digital") and cleaned_data.get("file_field") is None:
raise ValidationError({"file_field": "Digitale Rechnung fehlt."})
return cleaned_data
class BillCreateForm(forms.ModelForm):
# Bank data
name_text = forms.CharField(required=False, label="Kontoinhaber:in", initial="", max_length=128)
iban_text = forms.CharField(required=False, label="IBAN", initial="", max_length=34)
bic_text = forms.CharField(required=False, label="BIC", initial="", max_length=11)
saving = forms.BooleanField(
required=False,
label="Bankdaten für die nächsten Rechnungen speichern.",
initial=False,
)
# Resolution
resolution_text = forms.CharField(
required=False,
label="Beschlussnummer",
initial="",
max_length=128,
)
class Meta:
model = Bill
fields = [
"bill_creator",
"date",
"invoice",
"amount",
"purpose",
"affiliation",
"payer",
"only_digital",
"file_field",
"comment",
"resolution",
]
labels = {
"date": "Rechnungsdatum",
"invoice": "Rechnungsaussteller",
"amount": "Betrag (EUR)",
"purpose": "Verwendungszweck",
"affiliation": "Abrechnungsbudget",
"payer": "Ursprüngliche Bezahlmethode",
"only_digital": "Ich habe nur eine digitale Rechnung.",
"file_field": "Rechnung hochladen (PDF- und Bildformate erlaubt)",
"comment": "Kommentar",
}
widgets = {
"date": DateInput(format=("%Y-%m-%d")),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop("user") if "user" in kwargs else None
super().__init__(*args, **kwargs) # to get the self.fields set
member = Member.objects.get(username=user.username)
self.fields["bill_creator"].initial = member
self.fields["bill_creator"].disabled = True
self.fields["bill_creator"].required = True
self.fields["invoice"].placeholder = "Firmenname\nStraße\nPLZ und Ort"
self.fields["invoice"].rows = 4
# Bank data fields
self.fields["payer"].autofocus = True
bank_data = BankData.objects.filter(
Q(bankdata_creator=member) & Q(is_disabled=False),
).first()
if bank_data is not None:
self.fields["name_text"].initial = bank_data.name
self.fields["iban_text"].initial = bank_data.iban
self.fields["bic_text"].initial = bank_data.bic
self.fields["saving"].initial = True
def clean(self):
return get_cleaned_data(super().clean())
class BillUpdateForm(forms.ModelForm):
# Bank data
name_text = forms.CharField(required=False, label="Kontoinhaber:in", initial="", max_length=128)
iban_text = forms.CharField(required=False, label="IBAN", initial="", max_length=34)
bic_text = forms.CharField(required=False, label="BIC", initial="", max_length=11)
saving = forms.BooleanField(
required=False,
label="Bankdaten für die nächsten Rechnungen speichern.",
initial=False,
)
# only digital bill
only_digital_new = forms.BooleanField(
required=False,
label="Ich habe eine neue digitale Rechnung.",
initial=False,
)
# Resolution
resolution_text = forms.CharField(
required=False,
label="Beschlussnummer",
initial="",
max_length=128,
)
class Meta:
model = Bill
fields = [
"bill_creator",
"date",
"invoice",
"amount",
"purpose",
"affiliation",
"payer",
"only_digital",
"file_field",
"comment",
"status",
"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": "Neue Rechnung hochladen (PDF- und Bildformate erlaubt)",
"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"].initial = kwargs["instance"].bill_creator
self.fields["bill_creator"].disabled = True
self.fields["bill_creator"].required = True
self.fields["status"].disabled = True
# Config for textarea of invoice. Calc rows for a better view.
if (rows := kwargs["instance"].invoice.count("\n") + 1) < 3:
rows = 3
self.fields["invoice"].rows = rows
# Config for textarea of comment. Calc rows for a better view.
rows = kwargs["instance"].comment.count("\n") + 1
self.fields["comment"].rows = rows
if kwargs["instance"].status == Bill.Status.INCOMPLETED:
# 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["saving"].initial = not kwargs["instance"].bankdata.is_disabled
# Resolution fields
if kwargs["instance"].resolution:
_name = kwargs["instance"].resolution.name
self.fields["resolution_text"].initial = _name
self.fields["payer"].autofocus = True
else:
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["name_text"].required = True
self.fields["iban_text"].initial = kwargs["instance"].bankdata.iban
self.fields["iban_text"].required = True
self.fields["bic_text"].initial = kwargs["instance"].bankdata.bic
self.fields["bic_text"].required = True
self.fields["saving"].initial = not kwargs["instance"].bankdata.is_disabled
self.fields["name_text"].disabled = True
self.fields["iban_text"].disabled = True
self.fields["bic_text"].disabled = True
self.fields["saving"].disabled = True
# Resolution fields
if kwargs["instance"].resolution:
_name = kwargs["instance"].resolution.name
self.fields["resolution_text"].initial = _name
self.fields["resolution_text"].disabled = True
# Comment disabled when bill is cleared or finished
if kwargs["instance"].status != Bill.Status.SUBMITTED:
self.fields["comment"].disabled = True
self.fields["comment"].autofocus = True
def clean(self):
return get_cleaned_data(super().clean())
class ResolutionCreateForm(forms.ModelForm):
class Meta:
model = Resolution
fields = [
"option",
"name",
"date",
"voting",
"voting_text",
]
labels = {
"option": "Beschluss",
"date": "Datum",
"voting": "Abstimmungsverhalten",
"voting_text": "Abstimmungstext",
}
widgets = {
"date": DateInput(format=("%Y-%m-%d")),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # to get the self.fields set
self.fields["option"].autofocus = True
self.fields["voting_text"].rows = 3
class ResolutionUpdateForm(forms.ModelForm):
class Meta:
model = Resolution
fields = [
"option",
"name",
"date",
"voting",
"voting_text",
]
labels = {
"option": "Beschluss",
"date": "Datum",
"voting": "Abstimmungsverhalten",
"voting_text": "Abstimmungstext",
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # to get the self.fields set
self.fields["date"].disabled = True
self.fields["option"].autofocus = True
# Config for textarea of comment. Calc rows for a better view.
self.fields["voting_text"].cols = 30
rows = (
len(kwargs["instance"].voting_text) / 90
+ kwargs["instance"].voting_text.count("\n")
+ 1
)
self.fields["voting_text"].rows = rows
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
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- und Bildformate erlaubt)",
"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
# Displayed only permanent and max 2 years old finance resolutions.
self.fields["resolution"].queryset = self.fields["resolution"].queryset.filter(
(
Q(option=Resolution.Option.FINANCE)
& Q(date__gt=timezone.now().date() - relativedelta(years=2))
)
| Q(option=Resolution.Option.PERMANENT)
)
# Delete wiref id from list if there are already 10 bills in wiref form.
qs = (
self.fields["wiref"].queryset.annotate(num_bills=Count("bill")).filter(num_bills__lt=10)
)
# delete wiref id from if status is not opened.
qs = qs.filter(status=Wiref.Status.OPENED)
# add wiref id if wiref is already transferred.
bill = kwargs.get("instance")
if bill is not None and bill.wiref is not None and bill.wiref.status != Wiref.Status.OPENED:
qs |= self.fields["wiref"].queryset.filter(wiref_id=bill.wiref.wiref_id)
self.fields["wiref"].disabled = True
self.fields["wiref"].widget.can_add_related = False
self.fields["wiref"].widget.can_change_related = False
self.fields["wiref"].widget.can_delete_related = False
self.fields["wiref"].queryset = qs.order_by("-wiref_id")
class ResolutionAdminForm(forms.ModelForm):
total = forms.CharField()
budget_remaining = forms.CharField()
class Meta:
model = Resolution
fields = "__all__"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # to get the self.fields set
budget = decimal.Decimal("0.0")
total = decimal.Decimal("0.0")
if resolution := kwargs.get("instance"):
for elem in Bill.objects.filter(resolution=resolution):
total += elem.amount
budget = resolution.budget
self.fields["total"].disabled = True
self.fields["total"].initial = total
self.fields["total"].label = "Gesamtsumme (EUR)"
self.fields["total"].required = False
self.fields["budget_remaining"].disabled = True
self.fields["budget_remaining"].initial = budget - total
self.fields["budget_remaining"].label = "Restbudget (EUR)"
self.fields["budget_remaining"].required = False
self.fields["budget"].required = False
if resolution is not None:
self.fields["id"].disabled = True
self.fields["id"].required = False
class WirefAdminForm(forms.ModelForm):
total = forms.CharField()
class Meta:
model = Wiref
fields = [
"wiref_id",
"status",
"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
self.fields["wiref_id"].required = True
wiref = kwargs.get("instance")
total = 0
if wiref is not None:
bills = Bill.objects.filter(wiref=wiref)
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