add creating resolution and view of them
This commit is contained in:
@@ -226,6 +226,41 @@ class ResolutionAdmin(admin.ModelAdmin):
|
||||
"total",
|
||||
]
|
||||
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
"name",
|
||||
"id",
|
||||
"date",
|
||||
"option",
|
||||
"is_visible",
|
||||
)
|
||||
},
|
||||
),
|
||||
(
|
||||
"Budget",
|
||||
{
|
||||
"fields": (
|
||||
"budget",
|
||||
"total",
|
||||
"budget_remaining",
|
||||
)
|
||||
},
|
||||
),
|
||||
(
|
||||
"Abstimmung",
|
||||
{
|
||||
"classes": ["collapse"],
|
||||
"fields": (
|
||||
"voting",
|
||||
"voting_text",
|
||||
),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
def add_view(self, request, form_url="", extra_context=None):
|
||||
extra_context = extra_context or {}
|
||||
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||
|
||||
@@ -102,6 +102,14 @@ class BillCreateForm(forms.ModelForm):
|
||||
only_digital = cleaned_data.get("only_digital")
|
||||
file_field = cleaned_data.get("file_field")
|
||||
|
||||
# check if resolution exists
|
||||
try:
|
||||
Resolution.objects.get(id=resolution)
|
||||
except:
|
||||
raise ValidationError(
|
||||
f"Es gibt keinen Beschluss mit dieser ID. (Eingegebene ID: {resolution})"
|
||||
)
|
||||
|
||||
# check that amount is valid because invalid amount is a NoneType.
|
||||
if amount:
|
||||
if amount > 30 and resolution == "":
|
||||
@@ -212,6 +220,29 @@ class BillUpdateForm(forms.ModelForm):
|
||||
self.fields["comment"].disabled = True
|
||||
|
||||
|
||||
class ResolutionCreateForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Resolution
|
||||
|
||||
fields = [
|
||||
"option",
|
||||
"date",
|
||||
"voting",
|
||||
"voting_text",
|
||||
]
|
||||
|
||||
labels = {
|
||||
"option": "Beschluss",
|
||||
"date": "Datum",
|
||||
"voting": "Abstimmungsverhalten",
|
||||
"voting_text": "Abstimmungstext",
|
||||
}
|
||||
|
||||
widgets = {
|
||||
"date": DateInput(format=("%Y-%m-%d")),
|
||||
}
|
||||
|
||||
|
||||
class BillInlineForm(forms.ModelForm):
|
||||
class Meta:
|
||||
fields = [
|
||||
@@ -273,6 +304,7 @@ class BillAdminForm(forms.ModelForm):
|
||||
|
||||
class ResolutionAdminForm(forms.ModelForm):
|
||||
total = forms.CharField()
|
||||
budget_remaining = forms.CharField()
|
||||
|
||||
class Meta:
|
||||
model = Resolution
|
||||
@@ -280,14 +312,16 @@ class ResolutionAdminForm(forms.ModelForm):
|
||||
fields = [
|
||||
"name",
|
||||
"id",
|
||||
"date",
|
||||
"option",
|
||||
"is_visible",
|
||||
"budget",
|
||||
"total",
|
||||
"budget_remaining",
|
||||
"voting",
|
||||
"voting_text",
|
||||
]
|
||||
|
||||
labels = {
|
||||
"id": "ID",
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs) # to get the self.fields set
|
||||
|
||||
@@ -302,6 +336,15 @@ class ResolutionAdminForm(forms.ModelForm):
|
||||
self.fields["total"].label = "Gesamtsumme (EUR)"
|
||||
self.fields["total"].required = False
|
||||
|
||||
budget = 0
|
||||
if resolution:
|
||||
budget = resolution.budget
|
||||
|
||||
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
|
||||
|
||||
|
||||
class WirefAdminForm(forms.ModelForm):
|
||||
total = forms.CharField()
|
||||
|
||||
@@ -27,11 +27,31 @@ class BankData(models.Model):
|
||||
|
||||
|
||||
class Resolution(models.Model):
|
||||
id = models.CharField(primary_key=True, max_length=128)
|
||||
name = models.CharField(max_length=128)
|
||||
id = models.CharField(
|
||||
primary_key=True, max_length=128, verbose_name="Beschlussnummer"
|
||||
)
|
||||
name = models.CharField(max_length=128, verbose_name="Bezeichnung")
|
||||
|
||||
is_visible = models.BooleanField(default=False, verbose_name="sichtbar")
|
||||
|
||||
class Option(models.TextChoices):
|
||||
NORMAL = "B", "normaler Beschluss"
|
||||
PERMANENT = "D", "Dauerbeschluss"
|
||||
FINANCE = "F", "Finanzbeschluss"
|
||||
FSREF = "R", "FsRef-Beschluss"
|
||||
|
||||
option = models.CharField(
|
||||
max_length=1, choices=Option.choices, verbose_name="Beschluss"
|
||||
)
|
||||
|
||||
date = models.DateField(verbose_name="Datum")
|
||||
voting = models.CharField(max_length=15, verbose_name="Abstimmungsverhalten")
|
||||
voting_text = models.TextField(verbose_name="Abstimmungstext")
|
||||
|
||||
budget = models.DecimalField(
|
||||
max_digits=7, decimal_places=2, default=0.00, verbose_name="Budget (EUR)"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Beschluss"
|
||||
verbose_name_plural = "Beschlüsse"
|
||||
@@ -39,6 +59,26 @@ class Resolution(models.Model):
|
||||
def __str__(self):
|
||||
return f"{self.name}"
|
||||
|
||||
def clean(self):
|
||||
if self.id == "":
|
||||
year = self.date.strftime("%y")
|
||||
week = self.date.strftime("%W")
|
||||
|
||||
_id = ""
|
||||
for nmb in range(99):
|
||||
_id = f"{year}{week}-{nmb + 1:02d}"
|
||||
if not Resolution.objects.filter(id=_id).exists():
|
||||
break
|
||||
else:
|
||||
raise ValidationError(
|
||||
f"Es wurden zu viele Beschlüsse in dieser Woche angelegt. (ID: {_id})"
|
||||
)
|
||||
|
||||
self.id = _id
|
||||
|
||||
if self.name == "":
|
||||
self.name = self.id
|
||||
|
||||
|
||||
class Wiref(models.Model):
|
||||
wiref_id = models.CharField(max_length=10, blank=True, null=True)
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import apps, views
|
||||
from .views import BillCreateView, BillCreateDoneView, BillListView, BillUpdateView
|
||||
from .views import (
|
||||
BillCreateDoneView,
|
||||
BillCreateView,
|
||||
BillListView,
|
||||
BillUpdateView,
|
||||
ResolutionCreateView,
|
||||
ResolutionListView,
|
||||
)
|
||||
|
||||
app_name = apps.FinanceConfig.name
|
||||
|
||||
@@ -14,4 +21,8 @@ urlpatterns = [
|
||||
BillCreateDoneView.as_view(),
|
||||
name="bill_create_done",
|
||||
),
|
||||
path(
|
||||
"create-resolution/", ResolutionCreateView.as_view(), name="resolution_create"
|
||||
),
|
||||
path("resolutions/", ResolutionListView.as_view(), name="resolution_list"),
|
||||
]
|
||||
|
||||
@@ -9,7 +9,7 @@ from django.views.generic.edit import CreateView, UpdateView
|
||||
from fet2020.utils import add_log_action
|
||||
from members.models import Member
|
||||
|
||||
from .forms import BankDataForm, BillCreateForm, BillUpdateForm
|
||||
from .forms import BankDataForm, BillCreateForm, BillUpdateForm, ResolutionCreateForm
|
||||
from .models import BankData, Bill, Resolution
|
||||
|
||||
|
||||
@@ -84,3 +84,19 @@ class BillUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
|
||||
|
||||
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 ResolutionListView(LoginRequiredMixin, ListView):
|
||||
model = Resolution
|
||||
template_name = "finance/resolution_list.html"
|
||||
|
||||
26
fet2020/templates/finance/resolution_create.html
Normal file
26
fet2020/templates/finance/resolution_create.html
Normal file
@@ -0,0 +1,26 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Neuen Beschluss eingeben{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Main Content -->
|
||||
<main class="container mx-auto w-full px-4 my-8 flex-1">
|
||||
<h1 class="page-title">Neuen Beschluss eingeben</h1>
|
||||
<div class="w-full h-full flex-1 flex justify-center items-center">
|
||||
<form action="" enctype="multipart/form-data" method="POST" class="w-full max-w-xs sm:max-w-prose sm:px-28 sm:py-4 grid grid-cols-1 gap-y-3 sm:gap-y-6 text-gray-900">
|
||||
{% csrf_token %}
|
||||
|
||||
{% include "baseform/non_field_errors.html" %}
|
||||
|
||||
{% include "baseform/select.html" with field=form.option %}
|
||||
{% include "baseform/date.html" with field=form.date %}
|
||||
{% include "baseform/text.html" with field=form.voting %}
|
||||
{% include "baseform/textarea.html" with field=form.voting_text %}
|
||||
|
||||
<div class="flex flex-col-reverse sm:flex-row gap-3 justify-end pt-4 sm:pt-0">
|
||||
<input type="submit" class="block btn btn-primary" value="Absenden">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock %}
|
||||
48
fet2020/templates/finance/resolution_list.html
Normal file
48
fet2020/templates/finance/resolution_list.html
Normal file
@@ -0,0 +1,48 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Beschlusssammlung{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Main Content -->
|
||||
<main class="container mx-auto w-full px-4 my-8 flex-1">
|
||||
<h1 class="page-title">Beschlusssammlung</h1>
|
||||
|
||||
<section>
|
||||
<div class="mx-auto max-w-prose flex flex-col gap-4">
|
||||
|
||||
{% for result in object_list %}
|
||||
<article class="flex-grow-0">
|
||||
<h2 class="line-clamp-1 hover:underline decoration-1 text-gray-800 dark:text-gray-200 font-medium">{{ result.id }}: {{ result.name }}</h2>
|
||||
<ul class="text-gray-700 dark:text-gray-300 text-sm sm:text-base">
|
||||
<li><i class="fa-fw text-gray-600 dark:text-gray-400 mr-1"></i>{{ result.get_option_display }}</li>
|
||||
<li><i class="fa-fw text-gray-600 dark:text-gray-400 mr-1"></i>{{ result.date }}</li>
|
||||
<li><i class="fa-fw text-gray-600 dark:text-gray-400 mr-1"></i>Abstimmungsverhalten: {{ result.voting }}</li>
|
||||
</ul>
|
||||
</article>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% if not object_list %}
|
||||
<section>
|
||||
<div class="mx-auto max-w-prose flex flex-col gap-4">
|
||||
<h2 class="mb-1 text-gray-700 dark:text-gray-200">Keinen Beschluss in dieser Liste.</h2>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<div class="flex flex-col gap-y-4 max-w-prose mx-auto text-gray-700 dark:text-gray-300">
|
||||
<section>
|
||||
<div class="flex flex-col md:flex-row gap-y-2 md:gap-y-0 md:gap-x-2 lg:justify-end mt-4">
|
||||
<a
|
||||
href="{% url 'finance:resolution_create' %}"
|
||||
class="btn btn-primary block md:flex-grow lg:flex-grow-0"
|
||||
>
|
||||
<i class="fa-solid fa-plus-square mr-2"></i>Beschluss eingeben
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock %}
|
||||
@@ -49,12 +49,24 @@
|
||||
<span class="text-sm font-medium">Neue Rechnung einreichen</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'finance:resolution_create' %}" class="flex items-center py-2 px-5 hover:bg-gray-100 dark:hover:bg-gray-600 hover:text-gray-900 dark:hover:text-white">
|
||||
<i class="fa-solid fa-plus mr-2"></i>
|
||||
<span class="text-sm font-medium">Neuen Beschluss eingeben</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'finance:bill_list' %}" class="flex items-center py-2 px-5 hover:bg-gray-100 dark:hover:bg-gray-600 hover:text-gray-900 dark:hover:text-white">
|
||||
<i class="fa-solid fa-list mr-2"></i>
|
||||
<span class="text-sm font-medium">Deine eingereichten Rechnungen</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'finance:resolution_list' %}" class="flex items-center py-2 px-5 hover:bg-gray-100 dark:hover:bg-gray-600 hover:text-gray-900 dark:hover:text-white">
|
||||
<i class="fa-solid fa-list mr-2"></i>
|
||||
<span class="text-sm font-medium">Beschlusssammlung</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user