Compare commits
8 Commits
1f3fc92f6b
...
4e278fccab
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e278fccab | |||
| e17d12a079 | |||
| 1cfe36197f | |||
| 2e55fae418 | |||
| c15d60ac6a | |||
| e98da4426a | |||
| 97f2425434 | |||
| 3adc98144f |
@@ -46,8 +46,6 @@ INSTALLED_APPS = [
|
|||||||
"ckeditor_uploader",
|
"ckeditor_uploader",
|
||||||
"easy_thumbnails",
|
"easy_thumbnails",
|
||||||
"rest_framework",
|
"rest_framework",
|
||||||
"softhyphen",
|
|
||||||
"django_crontab",
|
|
||||||
"django_filters",
|
"django_filters",
|
||||||
"django_static_jquery_ui",
|
"django_static_jquery_ui",
|
||||||
"fontawesomefree",
|
"fontawesomefree",
|
||||||
@@ -61,6 +59,7 @@ INSTALLED_APPS = [
|
|||||||
"gallery.apps.GalleryConfig",
|
"gallery.apps.GalleryConfig",
|
||||||
"intern.apps.InternConfig",
|
"intern.apps.InternConfig",
|
||||||
"finance.apps.FinanceConfig",
|
"finance.apps.FinanceConfig",
|
||||||
|
"rental.apps.RentalConfig",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -337,12 +336,6 @@ CKEDITOR_CONFIGS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# CRON JOBS
|
|
||||||
CRONJOBS = [
|
|
||||||
("0 16 * * *", "posts.cronjobs.check_to_send_agenda_mail"),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# ETHERPAD
|
# ETHERPAD
|
||||||
ETHERPAD_HOST = env("ETHERPAD_HOST").strip()
|
ETHERPAD_HOST = env("ETHERPAD_HOST").strip()
|
||||||
if not ETHERPAD_HOST or ETHERPAD_HOST == "":
|
if not ETHERPAD_HOST or ETHERPAD_HOST == "":
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ urlpatterns = [
|
|||||||
path("intern/", include("intern.urls")),
|
path("intern/", include("intern.urls")),
|
||||||
path("jobs/", include("blackboard.urls")),
|
path("jobs/", include("blackboard.urls")),
|
||||||
path("posts/", include("posts.urls")),
|
path("posts/", include("posts.urls")),
|
||||||
|
path("rental/", include("rental.urls")),
|
||||||
path("search/", include("search.urls")),
|
path("search/", include("search.urls")),
|
||||||
path(
|
path(
|
||||||
"discord/",
|
"discord/",
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class BillPeriodeFilter(admin.SimpleListFilter):
|
|||||||
|
|
||||||
def lookups(self, request, model_admin):
|
def lookups(self, request, model_admin):
|
||||||
qs = model_admin.get_queryset(request).order_by("-date")
|
qs = model_admin.get_queryset(request).order_by("-date")
|
||||||
if qs.exists() is not True:
|
if not qs.exists():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
@@ -203,9 +203,11 @@ class BillAdmin(admin.ModelAdmin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
actions = ["make_cleared", "make_finished"]
|
actions = ["make_cleared", "make_finished"]
|
||||||
|
autocomplete_fields = ["resolution"]
|
||||||
list_filter = ["status", "affiliation", "payer", BillPeriodeFilter]
|
list_filter = ["status", "affiliation", "payer", BillPeriodeFilter]
|
||||||
|
search_fields = ["purpose", "bankdata__name"]
|
||||||
|
show_facets = admin.ShowFacets.ALWAYS
|
||||||
ordering = ["-id"]
|
ordering = ["-id"]
|
||||||
search_fields = ["purpose"]
|
|
||||||
|
|
||||||
readonly_fields = [
|
readonly_fields = [
|
||||||
"get_bankdata_name",
|
"get_bankdata_name",
|
||||||
@@ -461,7 +463,7 @@ class FeeAdmin(admin.ModelAdmin):
|
|||||||
self.message_user(
|
self.message_user(
|
||||||
request,
|
request,
|
||||||
(
|
(
|
||||||
"Das PDF File konnte nicht generiert werden, weil der Status nicht auf "
|
"Das PDF-Dokument konnte nicht generiert werden, da der Status nicht auf "
|
||||||
"'Eingereicht' gesetzt ist."
|
"'Eingereicht' gesetzt ist."
|
||||||
),
|
),
|
||||||
messages.WARNING,
|
messages.WARNING,
|
||||||
@@ -669,7 +671,7 @@ class WirefAdmin(admin.ModelAdmin):
|
|||||||
else:
|
else:
|
||||||
self.message_user(
|
self.message_user(
|
||||||
request,
|
request,
|
||||||
"Das PDF File wurde nicht generiert, weil der Status nicht offen ist.",
|
"Das PDF-Dokument konnte nicht generiert werden, da der Status nicht auf 'Offen' gesetzt ist.",
|
||||||
messages.WARNING,
|
messages.WARNING,
|
||||||
)
|
)
|
||||||
return HttpResponseRedirect(".")
|
return HttpResponseRedirect(".")
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ class BillCreateForm(forms.ModelForm):
|
|||||||
self.fields["bill_creator"].required = True
|
self.fields["bill_creator"].required = True
|
||||||
|
|
||||||
self.fields["invoice"].placeholder = "Firmenname\nStraße\nPLZ und Ort"
|
self.fields["invoice"].placeholder = "Firmenname\nStraße\nPLZ und Ort"
|
||||||
self.fields["invoice"].cols = 30
|
|
||||||
self.fields["invoice"].rows = 4
|
self.fields["invoice"].rows = 4
|
||||||
|
|
||||||
# Bank data fields
|
# Bank data fields
|
||||||
@@ -212,13 +211,11 @@ class BillUpdateForm(forms.ModelForm):
|
|||||||
self.fields["status"].disabled = True
|
self.fields["status"].disabled = True
|
||||||
|
|
||||||
# Config for textarea of invoice. Calc rows for a better view.
|
# Config for textarea of invoice. Calc rows for a better view.
|
||||||
self.fields["invoice"].cols = 30
|
|
||||||
if (rows := kwargs["instance"].invoice.count("\n") + 1) < 3:
|
if (rows := kwargs["instance"].invoice.count("\n") + 1) < 3:
|
||||||
rows = 3
|
rows = 3
|
||||||
self.fields["invoice"].rows = rows
|
self.fields["invoice"].rows = rows
|
||||||
|
|
||||||
# Config for textarea of comment. Calc rows for a better view.
|
# Config for textarea of comment. Calc rows for a better view.
|
||||||
self.fields["comment"].cols = 30
|
|
||||||
rows = kwargs["instance"].comment.count("\n") + 1
|
rows = kwargs["instance"].comment.count("\n") + 1
|
||||||
self.fields["comment"].rows = rows
|
self.fields["comment"].rows = rows
|
||||||
|
|
||||||
@@ -477,7 +474,6 @@ class ResolutionCreateForm(forms.ModelForm):
|
|||||||
|
|
||||||
self.fields["option"].autofocus = True
|
self.fields["option"].autofocus = True
|
||||||
|
|
||||||
self.fields["voting_text"].cols = 30
|
|
||||||
self.fields["voting_text"].rows = 3
|
self.fields["voting_text"].rows = 3
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ class Bill(models.Model):
|
|||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
verbose_name="Kontodaten",
|
verbose_name="Bankdaten",
|
||||||
)
|
)
|
||||||
|
|
||||||
resolution = models.ForeignKey(
|
resolution = models.ForeignKey(
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class BillListView(LoginRequiredMixin, ListView):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs1 = (
|
qs1 = (
|
||||||
Fee.objects.filter(bankdata__bankdata_creator__username=self.request.user)
|
Fee.objects.filter(fee_creator__username=self.request.user)
|
||||||
.values("amount", "status", "id")
|
.values("amount", "status", "id")
|
||||||
.annotate(
|
.annotate(
|
||||||
date=F("date_start"), purpose=F("job"), model=Value("FEE", output_field=CharField())
|
date=F("date_start"), purpose=F("job"), model=Value("FEE", output_field=CharField())
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
# HOW TO ADD CRONJOBS
|
|
||||||
# write a cronjob function
|
|
||||||
# add cronjob to fet2020/settings.py
|
|
||||||
# add cronjob with cmd 'python3 fet2020/manage.py crontab add'
|
|
||||||
import logging
|
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
from .mails import send_agenda_mail
|
|
||||||
from .models import FetMeeting
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def check_to_send_agenda_mail():
|
|
||||||
agenda_date = timezone.now().date() + timedelta(days=2)
|
|
||||||
next_meeting = FetMeeting.objects.filter(event_start__date=agenda_date).first()
|
|
||||||
|
|
||||||
if next_meeting and next_meeting.has_agenda:
|
|
||||||
logger.info("Agenda für die %s soll gesendet werden.", next_meeting.slug)
|
|
||||||
send_agenda_mail(next_meeting)
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.mail import send_mail
|
|
||||||
from html2text import html2text
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def send_agenda_mail(meeting):
|
|
||||||
date = meeting.event_start.date().strftime("%d.%m.%Y")
|
|
||||||
time = meeting.event_start.time()
|
|
||||||
agenda = html2text(meeting.agenda_html)
|
|
||||||
|
|
||||||
msg = (
|
|
||||||
"Liebe Alle,\n\n"
|
|
||||||
"wir haben am " + str(date) + " um " + str(time) + " wieder eine FET-Sitzung.\n"
|
|
||||||
"du hast noch bis morgen "
|
|
||||||
+ str(time)
|
|
||||||
+ " Zeit, weitere Themen auf die Agenda zu schreiben: "
|
|
||||||
+ settings.HOST_NAME
|
|
||||||
+ "/posts/"
|
|
||||||
+ str(meeting.slug)
|
|
||||||
+ ".\n\n"
|
|
||||||
"Die aktuelle Agenda ist: \n\n" + agenda + "\n\n"
|
|
||||||
"LG deine FET"
|
|
||||||
)
|
|
||||||
|
|
||||||
if send_mail(
|
|
||||||
subject="Test - Agenda der FET Sitzung von " + str(date),
|
|
||||||
message=msg,
|
|
||||||
from_email="service@fet.at",
|
|
||||||
recipient_list=["patrick@fet.at"],
|
|
||||||
):
|
|
||||||
logger.info("Mail für die Agenda %s wurde gesendet.", meeting.slug)
|
|
||||||
else:
|
|
||||||
logger.info("Mail für die Agenda %s wurde nicht gesendet.", meeting.slug)
|
|
||||||
0
fet2020/rental/__init__.py
Normal file
0
fet2020/rental/__init__.py
Normal file
84
fet2020/rental/admin.py
Normal file
84
fet2020/rental/admin.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from .forms import RentalAdminForm, RentalItemAdminForm
|
||||||
|
from .models import Rental, RentalItem
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Rental)
|
||||||
|
class RentalAdmin(admin.ModelAdmin):
|
||||||
|
form = RentalAdminForm
|
||||||
|
model = Rental
|
||||||
|
|
||||||
|
list_display = [
|
||||||
|
"id",
|
||||||
|
"firstname",
|
||||||
|
"surname",
|
||||||
|
"status",
|
||||||
|
"date_start",
|
||||||
|
"date_end",
|
||||||
|
]
|
||||||
|
fieldsets = (
|
||||||
|
(
|
||||||
|
"Persönliche Daten",
|
||||||
|
{
|
||||||
|
"fields": (
|
||||||
|
("firstname", "surname"),
|
||||||
|
("organization", "matriculation_number"),
|
||||||
|
("email", "phone"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Verleih",
|
||||||
|
{
|
||||||
|
"fields": (
|
||||||
|
("date_start", "date_end"),
|
||||||
|
"reason",
|
||||||
|
"rentalitems",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Sonstiges",
|
||||||
|
{
|
||||||
|
"fields": (
|
||||||
|
"comment",
|
||||||
|
"status",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_view(self, request, form_url="", extra_context=None):
|
||||||
|
extra_context = extra_context or {}
|
||||||
|
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||||
|
return super().add_view(request, form_url, extra_context=extra_context)
|
||||||
|
|
||||||
|
def change_view(self, request, object_id, form_url="", extra_context=None):
|
||||||
|
extra_context = extra_context or {}
|
||||||
|
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||||
|
return super().change_view(request, object_id, form_url, extra_context=extra_context)
|
||||||
|
|
||||||
|
def save_model(self, request, obj, form, change):
|
||||||
|
obj.author = request.user
|
||||||
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(RentalItem)
|
||||||
|
class RentalItemAdmin(admin.ModelAdmin):
|
||||||
|
form = RentalItemAdminForm
|
||||||
|
model = RentalItem
|
||||||
|
|
||||||
|
def add_view(self, request, form_url="", extra_context=None):
|
||||||
|
extra_context = extra_context or {}
|
||||||
|
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||||
|
return super().add_view(request, form_url, extra_context=extra_context)
|
||||||
|
|
||||||
|
def change_view(self, request, object_id, form_url="", extra_context=None):
|
||||||
|
extra_context = extra_context or {}
|
||||||
|
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||||
|
return super().change_view(request, object_id, form_url, extra_context=extra_context)
|
||||||
|
|
||||||
|
def save_model(self, request, obj, form, change):
|
||||||
|
obj.author = request.user
|
||||||
|
super().save_model(request, obj, form, change)
|
||||||
12
fet2020/rental/apps.py
Normal file
12
fet2020/rental/apps.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
from django.db.models.signals import post_migrate
|
||||||
|
|
||||||
|
from fet2020.utils import create_perms
|
||||||
|
|
||||||
|
|
||||||
|
class RentalConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "rental"
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
post_migrate.connect(create_perms, sender=self)
|
||||||
60
fet2020/rental/forms.py
Normal file
60
fet2020/rental/forms.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.forms import DateInput
|
||||||
|
|
||||||
|
from .models import Rental, RentalItem
|
||||||
|
|
||||||
|
|
||||||
|
class DateInput(DateInput):
|
||||||
|
input_type = "date"
|
||||||
|
|
||||||
|
|
||||||
|
class RentalCreateForm(forms.ModelForm):
|
||||||
|
# Conformation
|
||||||
|
conformation = forms.BooleanField(
|
||||||
|
required=True,
|
||||||
|
label=(
|
||||||
|
"1. Fachschaft Elektrotechnik (FET) hat stets Vorrecht. 2. Bereits bestätigte Objekte "
|
||||||
|
"können storniert werden, falls FET sie selber braucht. 3. Sachen dürfen nur über das "
|
||||||
|
"Verleihsystem verborgt werden. 4. Objekte müssen pünktlich und gereinigt retouniert "
|
||||||
|
"werden. 5. Verleihpersonen entscheiden über Kaution (lediglich für Pünktlichkeit und "
|
||||||
|
"Reinheit) 6. Geht was kaputt, muss dies umgehend mitgeteilt werden und finanziell "
|
||||||
|
"dafür aufgekommen werden. "
|
||||||
|
),
|
||||||
|
initial=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Rental
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
"firstname",
|
||||||
|
"surname",
|
||||||
|
"matriculation_number",
|
||||||
|
"email",
|
||||||
|
"phone",
|
||||||
|
"organization",
|
||||||
|
"date_start",
|
||||||
|
"date_end",
|
||||||
|
"reason",
|
||||||
|
"comment",
|
||||||
|
"rentalitems",
|
||||||
|
]
|
||||||
|
|
||||||
|
widgets = {
|
||||||
|
"date_start": DateInput(format=("%Y-%m-%d")),
|
||||||
|
"date_end": DateInput(format=("%Y-%m-%d")),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RentalAdminForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Rental
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
widgets = {"rentalitems": forms.CheckboxSelectMultiple()}
|
||||||
|
|
||||||
|
|
||||||
|
class RentalItemAdminForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = RentalItem
|
||||||
|
fields = "__all__"
|
||||||
71
fet2020/rental/models.py
Normal file
71
fet2020/rental/models.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.forms import ValidationError
|
||||||
|
|
||||||
|
from .validators import PhoneNumberValidator
|
||||||
|
|
||||||
|
|
||||||
|
class RentalItem(models.Model):
|
||||||
|
name = models.CharField(verbose_name="Name", max_length=128)
|
||||||
|
description = models.CharField(
|
||||||
|
verbose_name="Beschreibung", max_length=128, blank=True, default=""
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Verleihgegenstand"
|
||||||
|
verbose_name_plural = "Verleihgegenstände"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Rental(models.Model):
|
||||||
|
firstname = models.CharField(max_length=128, verbose_name="Vorname")
|
||||||
|
surname = models.CharField(max_length=128, verbose_name="Nachname")
|
||||||
|
|
||||||
|
matriculation_number = models.CharField(verbose_name="Matrikelnummer", max_length=8)
|
||||||
|
email = models.EmailField(verbose_name="E-Mail")
|
||||||
|
phone = models.CharField(
|
||||||
|
verbose_name="Telefonnummer", max_length=32, validators=[PhoneNumberValidator()]
|
||||||
|
)
|
||||||
|
|
||||||
|
organization = models.CharField(verbose_name="Organisation", max_length=128)
|
||||||
|
|
||||||
|
date_start = models.DateField(verbose_name="Abholdatum")
|
||||||
|
date_end = models.DateField(verbose_name="Rückgabedatum")
|
||||||
|
|
||||||
|
reason = models.TextField(verbose_name="Grund der Ausleihe", max_length=500)
|
||||||
|
|
||||||
|
comment = models.TextField(verbose_name="Kommentar", max_length=500, blank=True, default="")
|
||||||
|
|
||||||
|
class Status(models.TextChoices):
|
||||||
|
SUBMITTED = "S", "Eingereicht"
|
||||||
|
APPROVED = "A", "Verleih genehmigt"
|
||||||
|
REJECTED = "J", "Verleih abgelehnt"
|
||||||
|
ISSUED = "I", "Verleihgegenstände ausgegeben"
|
||||||
|
RETURNED = "R", "Verleihgegenstände zurückgegeben"
|
||||||
|
|
||||||
|
status = models.CharField(
|
||||||
|
verbose_name="Status",
|
||||||
|
max_length=1,
|
||||||
|
choices=Status.choices,
|
||||||
|
default=Status.SUBMITTED,
|
||||||
|
)
|
||||||
|
|
||||||
|
rentalitems = models.ManyToManyField(
|
||||||
|
RentalItem,
|
||||||
|
verbose_name="Verleihgegenstände",
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Verleih"
|
||||||
|
verbose_name_plural = "Verleih"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"Verleih #{self.id}: {self.firstname} {self.surname}"
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
if not self.date_end:
|
||||||
|
self.date_end = self.date_start
|
||||||
|
|
||||||
|
if self.date_start > self.date_end:
|
||||||
|
raise ValidationError("Das Abholdatum muss vor dem Rückgabedatum liegen.")
|
||||||
3
fet2020/rental/tests.py
Normal file
3
fet2020/rental/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
16
fet2020/rental/urls.py
Normal file
16
fet2020/rental/urls.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import apps
|
||||||
|
from .views import RentalCreateDoneView, RentalCreateView, RentalListView
|
||||||
|
|
||||||
|
app_name = apps.RentalConfig.name
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("rental/", RentalListView.as_view(), name="index"),
|
||||||
|
path("request-rental/", RentalCreateView.as_view(), name="rental_create"),
|
||||||
|
path(
|
||||||
|
"request-rental/<int:pk>/done/",
|
||||||
|
RentalCreateDoneView.as_view(),
|
||||||
|
name="rental_create_done",
|
||||||
|
),
|
||||||
|
]
|
||||||
11
fet2020/rental/validators.py
Normal file
11
fet2020/rental/validators.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from django.core.validators import RegexValidator
|
||||||
|
from django.utils.deconstruct import deconstructible
|
||||||
|
|
||||||
|
|
||||||
|
@deconstructible
|
||||||
|
class PhoneNumberValidator(RegexValidator):
|
||||||
|
regex = r"^\+?1?\d{9,15}$"
|
||||||
|
message = (
|
||||||
|
"Telefonnummer muss in diesem Format +999999999999 eingegeben werden. Bis zu 15 Zahlen "
|
||||||
|
"sind erlaubt."
|
||||||
|
)
|
||||||
152
fet2020/rental/views.py
Normal file
152
fet2020/rental/views.py
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import calendar
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.views.generic import ListView, TemplateView
|
||||||
|
from django.views.generic.edit import CreateView
|
||||||
|
|
||||||
|
from .forms import RentalCreateForm
|
||||||
|
from .models import Rental, RentalItem
|
||||||
|
|
||||||
|
|
||||||
|
class RentalListView(ListView):
|
||||||
|
model = Rental
|
||||||
|
template_name = "rental/calendar.html"
|
||||||
|
|
||||||
|
# Month is the month displayed in the calendar (and should be the first day of the month)
|
||||||
|
month = None
|
||||||
|
# Rental items to filter
|
||||||
|
rentalitem_filters = []
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
# Get the rental items from the filter (max. 4)
|
||||||
|
self.rentalitem_filters = request.GET.getlist("rentalitems", [])[:4]
|
||||||
|
if not self.rentalitem_filters:
|
||||||
|
for rentalitem in RentalItem.objects.all()[:4]:
|
||||||
|
self.rentalitem_filters.append(rentalitem.name)
|
||||||
|
|
||||||
|
# Get the displayed month from the request
|
||||||
|
_date_str = request.GET.get("month", "")
|
||||||
|
if _date_str:
|
||||||
|
self.month = (
|
||||||
|
datetime.datetime.strptime(_date_str, "%Y-%m").replace(tzinfo=datetime.UTC).date()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.month = datetime.datetime.now(tz=datetime.UTC).date().replace(day=1)
|
||||||
|
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
# Calculate the day of the previous month from Monday
|
||||||
|
days_of_prev_month = []
|
||||||
|
|
||||||
|
if self.month.weekday() != calendar.MONDAY:
|
||||||
|
for i in range(1, 7):
|
||||||
|
day = self.month + datetime.timedelta(days=-i)
|
||||||
|
days_of_prev_month.append(day)
|
||||||
|
if day.weekday() == calendar.MONDAY:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Calculate the days of the next month until Sunday
|
||||||
|
last_day_of_month = self.month.replace(
|
||||||
|
day=calendar.monthrange(self.month.year, self.month.month)[1]
|
||||||
|
)
|
||||||
|
days_of_next_month = []
|
||||||
|
|
||||||
|
if last_day_of_month.weekday() != calendar.SUNDAY:
|
||||||
|
for i in range(1, 7):
|
||||||
|
day = last_day_of_month + datetime.timedelta(days=i)
|
||||||
|
days_of_next_month.append(day)
|
||||||
|
if day.weekday() == calendar.SUNDAY:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Calculate the days of the displayed month
|
||||||
|
days_of_month = [
|
||||||
|
self.month + datetime.timedelta(days=i)
|
||||||
|
for i in range((last_day_of_month - self.month).days + 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Create a dictionary with the rental items for each day
|
||||||
|
rental_dict = {}
|
||||||
|
for rental in self.get_queryset():
|
||||||
|
for day in days_of_month:
|
||||||
|
if rental["date_start"] <= day and rental["date_end"] >= day:
|
||||||
|
if day not in rental_dict:
|
||||||
|
rental_dict[day] = []
|
||||||
|
|
||||||
|
if rental["rentalitems__name"] not in rental_dict[day]:
|
||||||
|
rental_dict[day].append(rental["rentalitems__name"])
|
||||||
|
|
||||||
|
# Add the displayed, previous and next month
|
||||||
|
context["month"] = self.month
|
||||||
|
context["prev_month"] = self.month + datetime.timedelta(days=-1)
|
||||||
|
context["next_month"] = self.month + datetime.timedelta(
|
||||||
|
days=calendar.monthrange(self.month.year, self.month.month)[1] + 1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the days of the displayed, previous and next month
|
||||||
|
context["days_of_month"] = days_of_month
|
||||||
|
context["days_of_prev_month"] = sorted(days_of_prev_month)
|
||||||
|
context["days_of_next_month"] = days_of_next_month
|
||||||
|
|
||||||
|
# Get the current date for the calendar
|
||||||
|
context["today"] = datetime.datetime.now(tz=datetime.UTC).date()
|
||||||
|
|
||||||
|
# Add rental items to the context for the filter
|
||||||
|
context["rentalitems"] = RentalItem.objects.all()
|
||||||
|
|
||||||
|
# Add the selected rental items to the context for the filter
|
||||||
|
context["rentalitem_filters"] = {"rentalitems": self.rentalitem_filters}
|
||||||
|
|
||||||
|
context["rental_dict"] = rental_dict
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
qs = (
|
||||||
|
super()
|
||||||
|
.get_queryset()
|
||||||
|
.filter(
|
||||||
|
Q(status=Rental.Status.APPROVED)
|
||||||
|
| Q(status=Rental.Status.ISSUED)
|
||||||
|
| Q(status=Rental.Status.RETURNED)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
last_day_of_month = self.month.replace(
|
||||||
|
day=calendar.monthrange(self.month.year, self.month.month)[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Filter by date
|
||||||
|
qs_new = qs.filter(date_start__gte=self.month, date_start__lte=last_day_of_month)
|
||||||
|
qs_new |= qs.filter(date_end__gte=self.month, date_end__lte=last_day_of_month)
|
||||||
|
|
||||||
|
# Filter by rental items
|
||||||
|
qs = qs.filter(rentalitems__name__in=self.rentalitem_filters).distinct()
|
||||||
|
|
||||||
|
qs = qs.values("id", "date_start", "date_end", "rentalitems__name").distinct()
|
||||||
|
|
||||||
|
return qs
|
||||||
|
|
||||||
|
|
||||||
|
class RentalCreateView(CreateView):
|
||||||
|
form_class = RentalCreateForm
|
||||||
|
model = Rental
|
||||||
|
template_name = "rental/create.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
context["rentalitems_addinfo"] = RentalItem.objects.all()
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse("rental:rental_create_done", kwargs={"pk": self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
|
class RentalCreateDoneView(TemplateView):
|
||||||
|
template_name = "rental/create_done.html"
|
||||||
Binary file not shown.
@@ -21,7 +21,5 @@ class NonUserSearchView(SearchView):
|
|||||||
|
|
||||||
@authenticated_user
|
@authenticated_user
|
||||||
def index(request):
|
def index(request):
|
||||||
if request.user.is_authenticated:
|
view = FetUserSearchView if request.user.is_authenticated else NonUserSearchView
|
||||||
return FetUserSearchView.as_view()(request)
|
return view.as_view()(request)
|
||||||
|
|
||||||
return NonUserSearchView.as_view()(request)
|
|
||||||
|
|||||||
@@ -111,6 +111,7 @@
|
|||||||
<li class="{% if 'posts' in request.path %}active{% endif %}"><a href="{% url 'posts:index' %}">News</a></li>
|
<li class="{% if 'posts' in request.path %}active{% endif %}"><a href="{% url 'posts:index' %}">News</a></li>
|
||||||
<li class="{% if 'members' in request.path %}active{% endif %}"><a href="{% url 'members:index' %}">Fachschaft</a></li>
|
<li class="{% if 'members' in request.path %}active{% endif %}"><a href="{% url 'members:index' %}">Fachschaft</a></li>
|
||||||
<li class="{% if 'gallery' in request.path %}active{% endif %}"><a href="{% url 'gallery:index' %}">Galerie</a></li>
|
<li class="{% if 'gallery' in request.path %}active{% endif %}"><a href="{% url 'gallery:index' %}">Galerie</a></li>
|
||||||
|
<li class="{% if 'rental' in request.path %}active{% endif %}"><a href="{% url 'rental:index' %}">Verleih</a></li>
|
||||||
<li class="{% if 'jobs' in request.path %}active{% endif %}"><a href="{% url 'blackboard:index' %}">Jobs</a></li>
|
<li class="{% if 'jobs' in request.path %}active{% endif %}"><a href="{% url 'blackboard:index' %}">Jobs</a></li>
|
||||||
|
|
||||||
{% get_flatpages '/kontakt/' as pages %}
|
{% get_flatpages '/kontakt/' as pages %}
|
||||||
@@ -229,7 +230,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<hr class="legal-divider">
|
<hr class="legal-divider">
|
||||||
<p class="copyright">© {% now 'Y' %} FET - Alle Rechte vorbehalten.</p>
|
<p class="copyright">© {% now 'Y' %} FET - Alle Rechte vorbehalten.</p>
|
||||||
<p class="text-center">{% version %}.</p>
|
{% if request.user.is_authenticated %}
|
||||||
|
<p class="text-center">{% version %}</p>
|
||||||
|
{% endif %}
|
||||||
</footer>
|
</footer>
|
||||||
<div class="super-duper-awesome-signature font-normal" x-data="footerCounter">
|
<div class="super-duper-awesome-signature font-normal" x-data="footerCounter">
|
||||||
<span x-bind="footerFirst">Handcrafted </span><span x-bind="footerSecond">with </span><i class="fa-solid fa-heart" aria-label="love" @click="increase" x-bind="footerThird"></i><span x-bind="footerFourth"> by</span><span x-bind="footerFifth"> fet</span>
|
<span x-bind="footerFirst">Handcrafted </span><span x-bind="footerSecond">with </span><i class="fa-solid fa-heart" aria-label="love" @click="increase" x-bind="footerThird"></i><span x-bind="footerFourth"> by</span><span x-bind="footerFifth"> fet</span>
|
||||||
|
|||||||
20
fet2020/templates/baseform/email.html
Normal file
20
fet2020/templates/baseform/email.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<label>
|
||||||
|
<span>{{ field.label }} {% if not field.field.required %}(optional){% endif %}</span>
|
||||||
|
{% if field.errors %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<div class="alert-body">{{ field.errors }}</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="{{ field.name }}"
|
||||||
|
{% if field.value %}value="{{ field.value }}"{% endif %}
|
||||||
|
{% if field.field.required %}required{% endif %}
|
||||||
|
{% if field.field.disabled %}disabled{% endif %}
|
||||||
|
{% if field.field.autofocus %}autofocus{% endif %}
|
||||||
|
class="w-full"
|
||||||
|
>
|
||||||
|
{% if field.help_text %}
|
||||||
|
<small class="text-gray-700 dark:text-gray-200">{{ field.help_text }}</small>
|
||||||
|
{% endif %}
|
||||||
|
</label>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<small>Details zur ursprünglichen bereits bezahlten Rechnung angeben.</small>
|
<small>Details zur ursprünglichen bereits bezahlten Rechnung angeben.</small>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6">
|
<div class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6">
|
||||||
<div class="sm:col-span-4">
|
<div class="col-span-full">
|
||||||
{% include "baseform/textarea.html" with field=form.invoice %}
|
{% include "baseform/textarea.html" with field=form.invoice %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-full">
|
<div class="col-span-full">
|
||||||
@@ -59,7 +59,8 @@
|
|||||||
type="number"
|
type="number"
|
||||||
name="amount"
|
name="amount"
|
||||||
value={{ form.amount.value }}
|
value={{ form.amount.value }}
|
||||||
required
|
{% if form.amount.field.required %}required{% endif %}
|
||||||
|
{% if form.amount.field.disabled %}disabled{% endif %}
|
||||||
min="0.00"
|
min="0.00"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
placeholder="123,99"
|
placeholder="123,99"
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
<small>Details zur ursprünglichen bereits bezahlten Rechnung angeben.</small>
|
<small>Details zur ursprünglichen bereits bezahlten Rechnung angeben.</small>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6">
|
<div class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6">
|
||||||
<div class="sm:col-span-4">
|
<div class="col-span-full">
|
||||||
{% include "baseform/textarea.html" with field=form.invoice %}
|
{% include "baseform/textarea.html" with field=form.invoice %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-full">
|
<div class="col-span-full">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% load flatpages job_groups softhyphen_tags static %}
|
{% load flatpages job_groups static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
@@ -55,9 +55,9 @@
|
|||||||
|
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
{% if active_job_group %}
|
{% if active_job_group %}
|
||||||
<li class="internalLI">
|
<li class="internalLI hyphens-auto" lang="de">
|
||||||
<a href="{% url 'admin:members_jobgroup_change' active_job_group.id %}">
|
<a href="{% url 'admin:members_jobgroup_change' active_job_group.id %}">
|
||||||
<i class="fa-solid fa-pen-to-square mr-1"></i>{{ active_job_group.name|softhyphen|safe }} bearbeiten
|
<i class="fa-solid fa-pen-to-square mr-1"></i>{{ active_job_group.name|safe }} bearbeiten
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
{% extends 'members/index.html' %}
|
{% extends 'members/index.html' %}
|
||||||
|
|
||||||
{% load softhyphen_tags %}
|
|
||||||
|
|
||||||
{% block title %}{{ member.firstname }} {{ member.surname }}{% endblock %}
|
{% block title %}{{ member.firstname }} {{ member.surname }}{% endblock %}
|
||||||
|
|
||||||
{% block extraheader %}
|
{% block extraheader %}
|
||||||
@@ -24,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% if member.description %}
|
{% if member.description %}
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
{{ member.description|softhyphen|safe }}
|
{{ member.description|safe }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
188
fet2020/templates/rental/calendar.html
Normal file
188
fet2020/templates/rental/calendar.html
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}Verleih{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<main class="container mx-auto w-full px-4 my-8 flex-1">
|
||||||
|
<h1 class="page-title">Verleih</h1>
|
||||||
|
|
||||||
|
<section class="text-center my-6">
|
||||||
|
<p class="my-6 text-gray-900 dark:text-gray-100">
|
||||||
|
Willkommen bei unserem Verleih!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="{% url 'rental:rental_create' %}" class="page-subtitle block btn-small btn-primary max-w-xs mx-auto sm:w-max sm:mr-0 sm:ml-auto">
|
||||||
|
<i class="fa-solid fa-plus mr-1"></i> Verleih anfragen
|
||||||
|
</a>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<form action="" method="GET">
|
||||||
|
<section>
|
||||||
|
<div class="grid grid-cols-1 gap-x-6 gap-y-6 lg:grid-cols-6 sm:grid-cols-3 pb-6">
|
||||||
|
<button
|
||||||
|
id="filterDropdownButton"
|
||||||
|
data-dropdown-toggle="filterDropdown"
|
||||||
|
class="w-full md:w-auto flex items-center justify-center py-2 px-4 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<i class="h-4 w-4 mr-2 fa-solid fa-filter"></i>
|
||||||
|
Filter
|
||||||
|
<i class="-mr-1 ml-1.5 mt-1 w-5 h-5 fa-solid fa-chevron-down"></i>
|
||||||
|
</button>
|
||||||
|
<div id="filterDropdown" class="z-10 hidden w-56 p-3 bg-white rounded-lg shadow dark:bg-gray-700">
|
||||||
|
<h6 class="mb-3 text-sm font-medium text-gray-900 dark:text-white">Verleihgegenstände</h6>
|
||||||
|
<ul class="space-y-2 text-sm" aria-labelledby="filterDropdownButton">
|
||||||
|
{% for item in rentalitems %}
|
||||||
|
<li class="flex items-center">
|
||||||
|
<input
|
||||||
|
id="item_{{ item.id }}"
|
||||||
|
type="checkbox"
|
||||||
|
name="rentalitems"
|
||||||
|
value="{{ item.name }}"
|
||||||
|
{% for key, value in rentalitem_filters.items %}
|
||||||
|
{% if key == "rentalitems" and item.name in value %}
|
||||||
|
checked
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
class="w-4 h-4 bg-gray-100 border-gray-300 rounded text-primary-600 focus:ring-primary-500 dark:focus:ring-primary-600 dark:ring-offset-gray-700 focus:ring-2 dark:bg-gray-600 dark:border-gray-500"
|
||||||
|
>
|
||||||
|
<label for="item_{{ item.id }}" class="ml-2 text-sm font-medium text-gray-900 dark:text-gray-100">{{ item.name }}</label>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="block btn btn-primary" name="" value="Submit">Filter anwenden</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="text-center">
|
||||||
|
<div class="wrapper mx-auto bg-white rounded shadow max-w-full">
|
||||||
|
<div class="header flex justify-between border-b p-2">
|
||||||
|
<span class="text-lg font-bold">{{ month|date:'F Y' }}</span>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<button type="submit" class="p-1" name="month" value="{{ prev_month|date:'Y-m' }}">
|
||||||
|
<i class="fa-regular fa-circle-left"></i>
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="p-1" name="month" value="{{ next_month|date:'Y-m' }}">
|
||||||
|
<i class="fa-regular fa-circle-right"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table-fixed w-full mx-auto">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="p-2 border-r h-10 xl:text-sm text-xs">
|
||||||
|
<span class="xl:block lg:block md:block sm:block hidden">Monday</span>
|
||||||
|
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Mon</span>
|
||||||
|
</th>
|
||||||
|
<th class="p-2 border-r h-10 xl:text-sm text-xs">
|
||||||
|
<span class="xl:block lg:block md:block sm:block hidden">Tuesday</span>
|
||||||
|
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Tue</span>
|
||||||
|
</th>
|
||||||
|
<th class="p-2 border-r h-10 xl:text-sm text-xs">
|
||||||
|
<span class="xl:block lg:block md:block sm:block hidden">Wednesday</span>
|
||||||
|
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Wed</span>
|
||||||
|
</th>
|
||||||
|
<th class="p-2 border-r h-10 xl:text-sm text-xs">
|
||||||
|
<span class="xl:block lg:block md:block sm:block hidden">Thursday</span>
|
||||||
|
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Thu</span>
|
||||||
|
</th>
|
||||||
|
<th class="p-2 border-r h-10 xl:text-sm text-xs">
|
||||||
|
<span class="xl:block lg:block md:block sm:block hidden">Friday</span>
|
||||||
|
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Fri</span>
|
||||||
|
</th>
|
||||||
|
<th class="p-2 border-r h-10 xl:text-sm text-xs">
|
||||||
|
<span class="xl:block lg:block md:block sm:block hidden">Saturday</span>
|
||||||
|
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Sat</span>
|
||||||
|
</th>
|
||||||
|
<th class="p-2 border-r h-10 xl:text-sm text-xs">
|
||||||
|
<span class="xl:block lg:block md:block sm:block hidden">Sunday</span>
|
||||||
|
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Sun</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for day in days_of_prev_month %}
|
||||||
|
{% if day.weekday == 0 %}
|
||||||
|
<tr class="text-center h-20">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<td class="border p-1 h-40">
|
||||||
|
<div class="flex flex-col h-40">
|
||||||
|
<div class="top h-5 w-full">
|
||||||
|
<span class="text-gray-500 text-sm">{{ day.day }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="bottom flex-grow h-30 py-1 w-full"></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for day in days_of_month %}
|
||||||
|
{% if day.weekday == 0 %}
|
||||||
|
<tr class="text-center h-20">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<td class="border p-1 h-40">
|
||||||
|
<div class="flex flex-col h-40">
|
||||||
|
<div class="top h-5 w-full">
|
||||||
|
{% if day == today %}
|
||||||
|
<span class="text-gray-100 dark:text-gray-900 border-2 border-blue-900 dark:border-blue-100 rounded-full bg-blue-900 dark:bg-blue-100">{{ day.day }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-900 dark:text-gray-100">{{ day.day }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for key, names in rental_dict.items %}
|
||||||
|
{% if key == day %}
|
||||||
|
{% for name in names %}
|
||||||
|
<div class="bottom h-30 py-1 w-full">
|
||||||
|
<div class="event bg-purple-400 text-white rounded p-1 text-sm">
|
||||||
|
<span class="event-name whitespace-nowrap 2xl:block xl:hidden lg:hidden md:hidden sm:hidden hidden">{{ name|truncatechars:26 }}</span>
|
||||||
|
<span class="event-name whitespace-nowrap 2xl:hidden xl:block lg:hidden md:hidden sm:hidden hidden">{{ name|truncatechars:20 }}</span>
|
||||||
|
<span class="event-name whitespace-nowrap 2xl:hidden xl:hidden lg:block md:hidden sm:hidden hidden">{{ name|truncatechars:15 }}</span>
|
||||||
|
<span class="event-name whitespace-nowrap 2xl:hidden xl:hidden lg:hidden md:block sm:hidden hidden">{{ name|truncatechars:10 }}</span>
|
||||||
|
<span class="event-name whitespace-nowrap 2xl:hidden xl:hidden lg:hidden md:hidden sm:block hidden">{{ name|truncatechars:6 }}</span>
|
||||||
|
<span class="event-name whitespace-nowrap 2xl:hidden xl:hidden lg:hidden md:hidden sm:hidden block">{{ name|truncatechars:3 }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% empty %}
|
||||||
|
<div class="bottom flex-grow h-30 py-1 w-full"></div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{% if day.weekday == 6 %}
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for day in days_of_next_month %}
|
||||||
|
<td class="border p-1 h-40">
|
||||||
|
<div class="flex flex-col h-40">
|
||||||
|
<div class="top h-5 w-full">
|
||||||
|
<span class="text-gray-500 text-sm">{{ day.day }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="bottom flex-grow h-30 py-1 w-full"></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{% if day.weekday == 6 %}
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
{% endblock content %}
|
||||||
112
fet2020/templates/rental/create.html
Normal file
112
fet2020/templates/rental/create.html
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Verleih Anfrage{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="container mx-auto w-full px-4 my-8 flex-1">
|
||||||
|
<h1 class="page-title">Verleih Anfrage</h1>
|
||||||
|
|
||||||
|
<form action="" enctype="multipart/form-data" method="POST" class="multiSectionForm max-w-2xl">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% include "baseform/non_field_errors.html" %}
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Persönliche Daten</h2>
|
||||||
|
<small>Bitte geben Sie Ihre persönlichen Daten ein.</small>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6">
|
||||||
|
<div class="sm:col-span-3">
|
||||||
|
{% include "baseform/text.html" with field=form.firstname %}
|
||||||
|
</div>
|
||||||
|
<div class="sm:col-span-3">
|
||||||
|
{% include "baseform/text.html" with field=form.surname %}
|
||||||
|
</div>
|
||||||
|
<div class="sm:col-span-3">
|
||||||
|
{% include "baseform/text.html" with field=form.organization %}
|
||||||
|
</div>
|
||||||
|
<div class="sm:col-span-3">
|
||||||
|
{% include "baseform/text.html" with field=form.matriculation_number %}
|
||||||
|
</div>
|
||||||
|
<div class="sm:col-span-3">
|
||||||
|
{% include "baseform/email.html" with field=form.email %}
|
||||||
|
</div>
|
||||||
|
<div class="sm:col-span-3">
|
||||||
|
{% include "baseform/text.html" with field=form.phone %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Verleihgegenstände</h2>
|
||||||
|
<small>Wählen Sie die gewünschten Verleihgegenstände aus.</small>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6 pb-6 col-span-full">
|
||||||
|
{% if form.rentalitems.errors %}
|
||||||
|
<div class="col-span-full alert alert-danger">
|
||||||
|
<div class="alert-body">{{ form.rentalitems.errors }}</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div id="{{ form.rentalitems.auto_id }}" class="col-span-full">
|
||||||
|
{% for elem in form.rentalitems %}
|
||||||
|
<div class="col-span-2 mb-2">
|
||||||
|
|
||||||
|
<label for="{{ elem.id_for_label }}">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="{{ elem.id_for_label }}"
|
||||||
|
name="{{ form.rentalitems.html_name }}"
|
||||||
|
value="{{ elem.data.value }}"
|
||||||
|
class="rounded border-gray-300 dark:border-none text-proprietary shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50"
|
||||||
|
>
|
||||||
|
<span>{{ elem.choice_label }}</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{% for item in rentalitems_addinfo %}
|
||||||
|
{% if item.name == elem.choice_label and item.description %}
|
||||||
|
<p class="text-xs text-gray-700 dark:text-gray-200">{{ item.description }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6">
|
||||||
|
<div class="sm:col-span-3">
|
||||||
|
{% include "baseform/date.html" with field=form.date_start %}
|
||||||
|
</div>
|
||||||
|
<div class="sm:col-span-3">
|
||||||
|
{% include "baseform/date.html" with field=form.date_end %}
|
||||||
|
</div>
|
||||||
|
<div class="col-span-full">
|
||||||
|
{% include "baseform/textarea.html" with field=form.reason %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Zusätzliche Informationen</h2>
|
||||||
|
<small>Hier können Sie zusätzliche Informationen, Anliegen und Sonstiges angeben.</small>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6">
|
||||||
|
<div class="col-span-full">
|
||||||
|
{% include "baseform/textarea.html" with field=form.comment %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6">
|
||||||
|
<div class="col-span-full">
|
||||||
|
{% include "baseform/checkbox.html" with field=form.conformation %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="flex justify-end">
|
||||||
|
<button type="submit" class="btn btn-primary w-full sm:w-auto" value="Einreichen">Anfrage abschicken</button>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
{% endblock content %}
|
||||||
17
fet2020/templates/rental/create_done.html
Normal file
17
fet2020/templates/rental/create_done.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Verleihanfrage erfolgreich eingereicht{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="container mx-auto w-full px-4 my-8 flex-1">
|
||||||
|
<section class="w-full text-center">
|
||||||
|
<p class="mt-6 text-gray-900 dark:text-gray-100">
|
||||||
|
Die Verleihanfrage mit der Nummer #{{ pk }} wurde erfolgreich eingereicht.
|
||||||
|
</p>
|
||||||
|
<div class="mt-10 flex items-center justify-center">
|
||||||
|
<a href="{% url 'home' %}" type="submit" class="block btn btn-primary">Zur Startseite</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
{% endblock content %}
|
||||||
Reference in New Issue
Block a user