Files
fet2020/fet2020/finance/views.py
2025-07-05 12:07:50 +02:00

249 lines
7.9 KiB
Python

from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.db.models import CharField, Q, Value
from django.shortcuts import redirect
from django.urls import reverse, reverse_lazy
from django.views.generic import ListView, TemplateView
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView
from fet2020.utils import add_log_action
from posts.models import FetMeeting
from .forms import (
BillCreateForm,
BillUpdateForm,
ResolutionCreateForm,
ResolutionUpdateForm,
)
from .models import BankData, Bill, Resolution
def set_bankdata(
creator, name: str, iban: str, bic: str, saving: bool, address: str = ""
) -> BankData:
if not name or not iban or not bic:
return None
# Replace whitespaces in iban and bic text.
iban = iban.replace(" ", "")
bic = bic.replace(" ", "")
obj, created = BankData.objects.get_or_create(
name=name,
iban=iban,
bic=bic,
defaults={"bankdata_creator": creator, "is_disabled": not saving, "address": address},
)
if not created and address:
BankData.objects.filter(id=obj.id).update(address=address)
if saving:
# Disable old bank data.
qs = BankData.objects.filter(
~Q(id=obj.id) & Q(bankdata_creator=obj.bankdata_creator) & Q(is_disabled=False)
)
qs.update(is_disabled=True)
return obj
class BillCreateView(LoginRequiredMixin, CreateView):
form_class = BillCreateForm
model = Bill
template_name = "finance/bill_create.html"
def form_valid(self, form):
# Get or create bankdata object.
creator = form.cleaned_data["bill_creator"]
name = form.cleaned_data["name_text"]
iban = form.cleaned_data["iban_text"]
bic = form.cleaned_data["bic_text"]
saving = form.cleaned_data["saving"]
form.instance.bankdata = set_bankdata(creator, name, iban, bic, saving)
add_log_action(self.request, form, "finance", "bill", True)
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
# Request user for bill creator.
kwargs["user"] = self.request.user
return kwargs
def get_success_url(self):
return reverse("finance:bill_create_done", kwargs={"pk": self.object.pk})
class BillCreateDoneView(LoginRequiredMixin, TemplateView):
template_name = "finance/bill_create_done.html"
class BillListView(LoginRequiredMixin, ListView):
model = Bill
template_name = "finance/index.html"
paginate_by = 10
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["bill_status"] = Bill.Status
return context
def get_queryset(self):
qs = (
Bill.objects.filter(bill_creator__username=self.request.user)
.values("amount", "status", "id", "date", "purpose")
.annotate(model=Value("BILL", output_field=CharField()))
)
return qs.order_by("-date", "purpose")
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):
if self.object.status == Bill.Status.INCOMPLETED:
# Set status to submitted if changes are valid and bill is incompleted.
self.object.status = Bill.Status.SUBMITTED
# Override only_digital db value by value of new only_digital.
if "file_field" in form.changed_data:
self.object.only_digital = form.cleaned_data["only_digital_new"]
# Get or create bankdata object.
creator = form.cleaned_data["bill_creator"]
name = form.cleaned_data["name_text"]
iban = form.cleaned_data["iban_text"]
bic = form.cleaned_data["bic_text"]
saving = form.cleaned_data["saving"]
form.instance.bankdata = set_bankdata(creator, name, iban, bic, saving)
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):
return self.get_object().bill_creator.username == self.request.user.username
def handle_no_permission(self):
return redirect("finance:bill_list")
class ResolutionCreateView(LoginRequiredMixin, CreateView):
form_class = ResolutionCreateForm
model = Resolution
success_url = reverse_lazy("finance:resolution_list")
template_name = "finance/resolution_create.html"
def form_valid(self, form):
add_log_action(self.request, form, "finance", "resolution", True)
return super().form_valid(form)
class ResolutionDetailView(LoginRequiredMixin, DetailView):
model = Resolution
pk_url_kwarg = "id"
template_name = "finance/resolution_detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["fetmeeting"] = (
FetMeeting.objects.get_queryset().filter(date=self.object.date).first()
)
return context
class ResolutionListView(LoginRequiredMixin, ListView):
model = Resolution
template_name = "finance/resolution_list.html"
ordering = ["-id"]
paginate_by = 10
_per_page = 10
_per_page_lst = ["10", "20", "50", "Alle"]
def get(self, request, *args, **kwargs):
self.q = request.GET.get("q", "")
self.options_filters = request.GET.getlist("options", [])
self._per_page = request.GET.get("paginate_by", "10")
if self._per_page == "Alle":
self.paginate_by = None
else:
self.paginate_by = self._per_page
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["q"] = self.q
# Add selected and all options
context["options"] = Resolution.Option.choices
context["selected_options"] = self.options_filters
# Add current per page value and list
context["per_page"] = self._per_page
context["per_page_values"] = self._per_page_lst
# Add paginator links
if context["is_paginated"]:
_page_obj = context["page_obj"]
base_url = "?"
for option in self.options_filters:
base_url += f"options={option}&".replace(" ", "+")
if self.q:
base_url += f"q={self.q}&".replace(" ", "+")
end_url = f"paginate_by={self._per_page}"
if _page_obj.has_previous():
context["prev_page"] = (
f"{base_url}page={_page_obj.previous_page_number()}&{end_url}"
)
context["first_page"] = f"{base_url}page=1&{end_url}"
if _page_obj.has_next():
context["next_page"] = f"{base_url}page={_page_obj.next_page_number()}&{end_url}"
context["last_page"] = f"{base_url}page={_page_obj.paginator.num_pages}&{end_url}"
return context
def get_queryset(self):
qs = super().get_queryset()
if self.q:
qs = qs.filter(Q(name__icontains=self.q) | Q(voting_text__icontains=self.q))
if self.options_filters:
filter_lst = [
elem[0] for elem in Resolution.Option.choices if elem[1] in self.options_filters
]
qs = qs.filter(option__in=filter_lst)
return qs
class ResolutionUpdateView(LoginRequiredMixin, UpdateView):
form_class = ResolutionUpdateForm
model = Resolution
pk_url_kwarg = "id"
success_url = reverse_lazy("finance:resolution_list")
template_name = "finance/resolution_update.html"
def form_valid(self, form):
add_log_action(self.request, form, "finance", "resolution", False)
return super().form_valid(form)