add creating resolution and view of them
This commit is contained in:
@@ -226,6 +226,41 @@ class ResolutionAdmin(admin.ModelAdmin):
|
|||||||
"total",
|
"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):
|
def add_view(self, request, form_url="", extra_context=None):
|
||||||
extra_context = extra_context or {}
|
extra_context = extra_context or {}
|
||||||
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||||
|
|||||||
@@ -102,6 +102,14 @@ class BillCreateForm(forms.ModelForm):
|
|||||||
only_digital = cleaned_data.get("only_digital")
|
only_digital = cleaned_data.get("only_digital")
|
||||||
file_field = cleaned_data.get("file_field")
|
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.
|
# check that amount is valid because invalid amount is a NoneType.
|
||||||
if amount:
|
if amount:
|
||||||
if amount > 30 and resolution == "":
|
if amount > 30 and resolution == "":
|
||||||
@@ -212,6 +220,29 @@ class BillUpdateForm(forms.ModelForm):
|
|||||||
self.fields["comment"].disabled = True
|
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 BillInlineForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = [
|
fields = [
|
||||||
@@ -273,6 +304,7 @@ class BillAdminForm(forms.ModelForm):
|
|||||||
|
|
||||||
class ResolutionAdminForm(forms.ModelForm):
|
class ResolutionAdminForm(forms.ModelForm):
|
||||||
total = forms.CharField()
|
total = forms.CharField()
|
||||||
|
budget_remaining = forms.CharField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Resolution
|
model = Resolution
|
||||||
@@ -280,14 +312,16 @@ class ResolutionAdminForm(forms.ModelForm):
|
|||||||
fields = [
|
fields = [
|
||||||
"name",
|
"name",
|
||||||
"id",
|
"id",
|
||||||
|
"date",
|
||||||
|
"option",
|
||||||
"is_visible",
|
"is_visible",
|
||||||
|
"budget",
|
||||||
"total",
|
"total",
|
||||||
|
"budget_remaining",
|
||||||
|
"voting",
|
||||||
|
"voting_text",
|
||||||
]
|
]
|
||||||
|
|
||||||
labels = {
|
|
||||||
"id": "ID",
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs) # to get the self.fields set
|
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"].label = "Gesamtsumme (EUR)"
|
||||||
self.fields["total"].required = False
|
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):
|
class WirefAdminForm(forms.ModelForm):
|
||||||
total = forms.CharField()
|
total = forms.CharField()
|
||||||
|
|||||||
@@ -27,11 +27,31 @@ class BankData(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class Resolution(models.Model):
|
class Resolution(models.Model):
|
||||||
id = models.CharField(primary_key=True, max_length=128)
|
id = models.CharField(
|
||||||
name = models.CharField(max_length=128)
|
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")
|
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:
|
class Meta:
|
||||||
verbose_name = "Beschluss"
|
verbose_name = "Beschluss"
|
||||||
verbose_name_plural = "Beschlüsse"
|
verbose_name_plural = "Beschlüsse"
|
||||||
@@ -39,6 +59,26 @@ class Resolution(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.name}"
|
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):
|
class Wiref(models.Model):
|
||||||
wiref_id = models.CharField(max_length=10, blank=True, null=True)
|
wiref_id = models.CharField(max_length=10, blank=True, null=True)
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from . import apps, views
|
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
|
app_name = apps.FinanceConfig.name
|
||||||
|
|
||||||
@@ -14,4 +21,8 @@ urlpatterns = [
|
|||||||
BillCreateDoneView.as_view(),
|
BillCreateDoneView.as_view(),
|
||||||
name="bill_create_done",
|
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 fet2020.utils import add_log_action
|
||||||
from members.models import Member
|
from members.models import Member
|
||||||
|
|
||||||
from .forms import BankDataForm, BillCreateForm, BillUpdateForm
|
from .forms import BankDataForm, BillCreateForm, BillUpdateForm, ResolutionCreateForm
|
||||||
from .models import BankData, Bill, Resolution
|
from .models import BankData, Bill, Resolution
|
||||||
|
|
||||||
|
|
||||||
@@ -84,3 +84,19 @@ class BillUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
|
|||||||
|
|
||||||
def handle_no_permission(self):
|
def handle_no_permission(self):
|
||||||
return redirect("finance:bill_list")
|
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>
|
<span class="text-sm font-medium">Neue Rechnung einreichen</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</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>
|
<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">
|
<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>
|
<i class="fa-solid fa-list mr-2"></i>
|
||||||
<span class="text-sm font-medium">Deine eingereichten Rechnungen</span>
|
<span class="text-sm font-medium">Deine eingereichten Rechnungen</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user