513 lines
16 KiB
Python
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
|