Compare commits

6 Commits

Author SHA1 Message Date
7b78368eb0 Set logging level for Image module to info 2025-07-16 22:53:07 +02:00
8939fe5776 improve form layout 2025-07-16 22:33:12 +02:00
96b2549503 better file display 2025-07-16 22:30:47 +02:00
60f231d908 fix css style 2025-07-16 21:16:56 +02:00
42b80bd143 add Verleihformular 2025-07-16 19:21:47 +02:00
15e8ffc3c8 remove dead code 2025-07-05 12:07:50 +02:00
17 changed files with 144 additions and 1488 deletions

View File

@@ -380,152 +380,6 @@ class BillAdmin(admin.ModelAdmin):
) )
# @admin.register(Fee)
# class FeeAdmin(admin.ModelAdmin):
# form = FeeAdminForm
# model = Fee
# list_display = ["id", "amount", "job", "fix_name_desc", "status_colored"]
# list_filter = ["status"]
# show_facets = admin.ShowFacets.ALWAYS
# ordering = ["-id"]
# readonly_fields = [
# "address",
# "get_qrcode",
# ]
# fieldsets = (
# (
# None,
# {
# "fields": (
# "fee_creator",
# "bankdata",
# "address",
# "get_qrcode",
# ),
# },
# ),
# (
# "Tätigkeit",
# {
# "fields": (
# "job",
# "date_start",
# "date_end",
# "amount",
# ),
# },
# ),
# (
# "Sonstiges",
# {
# "fields": (
# "comment",
# "status",
# "file_field",
# ),
# },
# ),
# )
# 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."
# extra_context["generate_fee_pdf"] = True
# return super().change_view(
# request,
# object_id,
# form_url,
# extra_context=extra_context,
# )
# def response_change(self, request, obj):
# if "_generate_fee_pdf" in request.POST:
# if generate_fee_pdf(obj):
# self.message_user(
# request,
# "Neue Honorarnote wurde generiert.",
# messages.SUCCESS,
# )
# else:
# self.message_user(
# request,
# (
# "Das PDF-Dokument konnte nicht generiert werden, da der Status nicht auf "
# "'Eingereicht' gesetzt ist."
# ),
# messages.WARNING,
# )
# return HttpResponseRedirect(".")
# return super().response_change(request, obj)
# def save_model(self, request, obj, form, change):
# # set status to submitted, if a file exists and status is opened.
# if (
# change
# and obj.file_field
# and obj.status == Fee.Status.SUBMITTED
# and "_generate_fee_pdf" not in request.POST
# ):
# obj.status = Fee.Status.APPROVED
# super().save_model(request, obj, form, change)
# @admin.display(description="Adresse")
# def address(self, obj):
# return obj.bankdata.address
# @admin.display(description="QR Code")
# def get_qrcode(self, obj):
# # QR Code is only set if status is approved.
# if obj.status != Fee.Status.APPROVED:
# return "-"
# try:
# qrcode = helpers.make_epc_qr(
# name=obj.bankdata.name,
# iban=obj.bankdata.iban,
# amount=obj.amount,
# text=f"Honorarnote Nr.{obj.id}",
# bic=obj.bankdata.bic,
# encoding="utf-8",
# )
# except Exception:
# return "Daten für QR Code ungültig"
# uri = qrcode.png_data_uri(scale=3.0)
# return format_html('<img src="{}">', uri)
# @admin.display(description="Name")
# def fix_name_desc(self, obj):
# return obj.bankdata.name
# @admin.display(description="Status")
# def status_colored(self, obj):
# # TODO: if there is a status without color, set nothing.
# colors = {
# Fee.Status.SUBMITTED: "red",
# Fee.Status.APPROVED: "darkorange",
# Fee.Status.PAYOUT: "green",
# Fee.Status.CLEARED: "DarkMagenta",
# }
# return format_html(
# '<b style="background:{color};">{status}</b>',
# color=colors[obj.status],
# status=obj.get_status_display(),
# )
@admin.register(Resolution) @admin.register(Resolution)
class ResolutionAdmin(admin.ModelAdmin): class ResolutionAdmin(admin.ModelAdmin):
form = ResolutionAdminForm form = ResolutionAdminForm

View File

@@ -283,171 +283,6 @@ class BillUpdateForm(forms.ModelForm):
return get_cleaned_data(super().clean()) return get_cleaned_data(super().clean())
# class FeeCreateForm(forms.ModelForm):
# # Bank data
# name_text = forms.CharField(required=True, label="Kontoinhaber:in", initial="", max_length=128)
# iban_text = forms.CharField(required=True, label="IBAN", initial="", max_length=34)
# bic_text = forms.CharField(required=True, label="BIC", initial="", max_length=11)
# address_text = forms.CharField(
# required=True, widget=forms.Textarea, label="Adresse", initial=""
# )
# saving = forms.BooleanField(
# required=False,
# label="Bankdaten für die nächsten Rechnungen speichern.",
# initial=False,
# )
# # Conformation
# conformation = forms.BooleanField(
# required=True,
# label=(
# "Hiermit bestätige ich, dass mir die relevanten rechtlichen und steuerlichen "
# "Bestimmungen im Zusammenhang mit Honorarnoten bekannt sind. Ich verpflichte "
# "mich, diese in Übereinstimmung mit den geltenden steuerlichen Vorschriften "
# "ordnungsgemäß zu melden."
# ),
# initial=False,
# )
# class Meta:
# model = Fee
# fields = [
# "fee_creator",
# "job",
# "date_start",
# "date_end",
# "amount",
# "comment",
# ]
# help_texts = {
# "date_end": "Bei einer leeren Eingabe Eingabe wird automatisch das Startdatum gesetzt."
# }
# labels = {
# "job": "Tätigkeitsbeschreibung",
# }
# widgets = {
# "date_start": DateInput(format=("%Y-%m-%d")),
# "date_end": 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["fee_creator"].initial = member
# self.fields["fee_creator"].disabled = True
# self.fields["fee_creator"].required = True
# self.fields["date_end"].required = False
# self.fields["address_text"].placeholder = "Straße\nPLZ und Ort"
# # Bank data fields
# bank_data = BankData.objects.filter(
# Q(bankdata_creator=member) & Q(is_disabled=False),
# ).first()
# if bank_data:
# 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["address_text"].initial = bank_data.address
# self.fields["saving"].initial = True
# class FeeUpdateForm(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)
# address_text = forms.CharField(
# required=False, widget=forms.Textarea, label="Adresse", initial=""
# )
# saving = forms.BooleanField(
# required=False,
# label="Bankdaten für die nächsten Rechnungen speichern.",
# initial=False,
# )
# class Meta:
# model = Fee
# fields = [
# "fee_creator",
# "job",
# "date_start",
# "date_end",
# "amount",
# "status",
# "comment",
# ]
# labels = {
# "job": "Tätigkeitsbeschreibung",
# }
# widgets = {
# "date_start": DateInput(format=("%Y-%m-%d")),
# "date_end": DateInput(format=("%Y-%m-%d")),
# }
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs) # to get the self.fields set
# self.fields["fee_creator"].initial = kwargs["instance"].fee_creator
# self.fields["fee_creator"].disabled = True
# self.fields["fee_creator"].required = True
# self.fields["status"].disabled = True
# # Config for textarea of job. Calc rows for a better view.
# if (rows := kwargs["instance"].job.count("\n") + 1) < 3:
# rows = 3
# self.fields["job"].rows = rows
# self.fields["job"].disabled = True
# self.fields["date_start"].disabled = True
# self.fields["date_end"].disabled = True
# self.fields["amount"].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["address_text"].initial = kwargs["instance"].bankdata.address
# 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["address_text"].disabled = True
# self.fields["saving"].disabled = True
# # Config for textarea of comment. Calc rows for a better view.
# rows = kwargs["instance"].comment.count("\n") + 1
# self.fields["comment"].rows = rows
# # 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
class ResolutionCreateForm(forms.ModelForm): class ResolutionCreateForm(forms.ModelForm):
class Meta: class Meta:
model = Resolution model = Resolution
@@ -603,28 +438,6 @@ class BillAdminForm(forms.ModelForm):
self.fields["wiref"].queryset = qs.order_by("-wiref_id") self.fields["wiref"].queryset = qs.order_by("-wiref_id")
# class FeeAdminForm(forms.ModelForm):
# class Meta:
# model = Fee
# fields = "__all__"
# help_texts = {
# "date_end": "Bei einer leeren Eingabe Eingabe wird automatisch das Startdatum gesetzt."
# }
# widgets = {
# "date": DateInput(format=("%Y-%m-%d")),
# }
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# self.fields["bankdata"].required = True
# self.fields["date_end"].required = False
class ResolutionAdminForm(forms.ModelForm): class ResolutionAdminForm(forms.ModelForm):
total = forms.CharField() total = forms.CharField()
budget_remaining = forms.CharField() budget_remaining = forms.CharField()

View File

@@ -1,3 +1,5 @@
from pathlib import Path
from django.core.validators import FileExtensionValidator, ValidationError from django.core.validators import FileExtensionValidator, ValidationError
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
@@ -38,71 +40,6 @@ class BankData(models.Model):
self.bic = self.bic.replace(" ", "") self.bic = self.bic.replace(" ", "")
# class Fee(models.Model):
# fee_creator = models.ForeignKey(
# Member,
# on_delete=models.PROTECT,
# blank=True,
# null=True,
# verbose_name="Verantwortliche:r",
# )
# bankdata = models.ForeignKey(
# BankData,
# on_delete=models.SET_NULL,
# blank=True,
# null=True,
# verbose_name="Bankdaten",
# )
# job = models.TextField(verbose_name="Tätigkeit")
# date_start = models.DateField(verbose_name="Start der Tätigkeit")
# date_end = models.DateField(verbose_name="Ende der Tätigkeit")
# amount = models.DecimalField(max_digits=7, decimal_places=2, verbose_name="Betrag (EUR)")
# class Status(models.TextChoices):
# SUBMITTED = "S", "Eingereicht"
# APPROVED = "A", "Für Überweisung freigegeben"
# PAYOUT = "P", "Ausbezahlt"
# CLEARED = "C", "An Dekanat verrechnet"
# status = models.CharField(
# max_length=1,
# choices=Status.choices,
# default=Status.SUBMITTED,
# verbose_name="Status",
# )
# date_created = models.DateTimeField(auto_now_add=True)
# file_field = models.FileField(
# upload_to="uploads/finance/fee/",
# validators=[FileExtensionValidator(["pdf"])],
# blank=True,
# null=True,
# verbose_name="Honorarnote",
# )
# comment = models.TextField(blank=True, default="", verbose_name="Kommentar")
# class Meta:
# verbose_name = "Honorar"
# verbose_name_plural = "Honorare"
# def __str__(self):
# return f"Honorar #{self.id} / {self.job}"
# def save(self, *args, **kwargs):
# if not self.date_end:
# self.date_end = self.date_start
# super().save(*args, **kwargs)
# @property
# def filename(self):
# return Path(self.file_field.name).name
class Resolution(models.Model): class Resolution(models.Model):
id = models.CharField(primary_key=True, max_length=128, verbose_name="Beschlussnummer") id = models.CharField(primary_key=True, max_length=128, verbose_name="Beschlussnummer")
name = models.CharField(max_length=128, verbose_name="Bezeichnung") name = models.CharField(max_length=128, verbose_name="Bezeichnung")
@@ -286,3 +223,6 @@ class Bill(models.Model):
def clean(self): def clean(self):
if self.status is None: if self.status is None:
self.status = Bill.Status.SUBMITTED self.status = Bill.Status.SUBMITTED
def filename(self):
return Path(self.file_field.name).name

View File

@@ -24,14 +24,6 @@ urlpatterns = [
BillCreateDoneView.as_view(), BillCreateDoneView.as_view(),
name="bill_create_done", name="bill_create_done",
), ),
# # Fee views
# path("create-fee/", FeeCreateView.as_view(), name="fee_create"),
# path(
# "create-fee/<int:pk>/done/",
# FeeCreateDoneView.as_view(),
# name="fee_create_done",
# ),
# path("fee/<int:pk>/", FeeUpdateView.as_view(), name="fee_update"),
# Resolution views # Resolution views
path("create-resolution/", ResolutionCreateView.as_view(), name="resolution_create"), path("create-resolution/", ResolutionCreateView.as_view(), name="resolution_create"),
path("resolutions/", ResolutionListView.as_view(), name="resolution_list"), path("resolutions/", ResolutionListView.as_view(), name="resolution_list"),

View File

@@ -80,58 +80,3 @@ def generate_pdf(wiref):
wiref.file_field.save(wiref_name, File(bytes_stream, wiref_name)) wiref.file_field.save(wiref_name, File(bytes_stream, wiref_name))
return True return True
# def generate_fee_pdf(fee: Fee):
# if not fee or fee.status != Fee.Status.SUBMITTED:
# return False
# # Get data for pdf
# data = {}
# data.update(
# {
# "Full_Name": fee.bankdata.name,
# "Adresse": fee.bankdata.address,
# # Change to the correct date format
# "Date": str(fee.date_created.strftime("%d.%m.%Y")),
# "Honorarnoten-Nummer": str(fee.pk),
# "Taetigkeit_1": fee.job,
# # Change to the correct date format
# "Date_1": str(fee.date_start.strftime("%d.%m.%Y")),
# # Change to the correct date format
# "Date_2": str(fee.date_end.strftime("%d.%m.%Y")),
# # Replace decimal separator from '.' to ','
# "EUR_1": str(fee.amount).replace(".", ","),
# "IBAN": fee.bankdata.iban,
# "BIC": fee.bankdata.bic,
# },
# )
# # Add mail only if a fet user create the fee
# if fee.fee_creator:
# mail = fee.fee_creator.mailaccount
# data.update(
# {
# "Email": mail,
# },
# )
# # Write data in pdf
# pdf_path = Path(Path(__file__).parent) / "static/fee/Honorarnote-Vorlage.pdf"
# reader = PdfReader(pdf_path)
# writer = PdfWriter()
# writer.append(reader)
# writer.update_page_form_field_values(
# writer.pages[0],
# data,
# )
# with io.BytesIO() as bytes_stream:
# writer.write(bytes_stream)
# # Save pdf in fee
# fee_name = f"Honorarnote-{fee.pk}.pdf"
# fee.file_field.save(fee_name, File(bytes_stream, fee_name))
# return True

View File

@@ -89,26 +89,17 @@ class BillListView(LoginRequiredMixin, ListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
# context["fee_status"] = Fee.Status
context["bill_status"] = Bill.Status context["bill_status"] = Bill.Status
return context return context
def get_queryset(self): def get_queryset(self):
# qs1 = (
# Fee.objects.filter(fee_creator__username=self.request.user)
# .values("amount", "status", "id")
# .annotate(
# date=F("date_start"), purpose=F("job"), model=Value("FEE", output_field=CharField())
# )
# )
qs = ( qs = (
Bill.objects.filter(bill_creator__username=self.request.user) Bill.objects.filter(bill_creator__username=self.request.user)
.values("amount", "status", "id", "date", "purpose") .values("amount", "status", "id", "date", "purpose")
.annotate(model=Value("BILL", output_field=CharField())) .annotate(model=Value("BILL", output_field=CharField()))
) )
# qs = qs1.union(qs2, all=True)
return qs.order_by("-date", "purpose") return qs.order_by("-date", "purpose")
@@ -146,57 +137,6 @@ class BillUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
return redirect("finance:bill_list") return redirect("finance:bill_list")
# class FeeCreateView(LoginRequiredMixin, CreateView):
# form_class = FeeCreateForm
# model = Fee
# template_name = "finance/fee/create.html"
# def form_valid(self, form):
# # Get or create bankdata object.
# creator = form.cleaned_data["fee_creator"]
# name = form.cleaned_data["name_text"]
# iban = form.cleaned_data["iban_text"]
# bic = form.cleaned_data["bic_text"]
# address = form.cleaned_data["address_text"]
# saving = form.cleaned_data["saving"]
# form.instance.bankdata = set_bankdata(creator, name, iban, bic, saving, address)
# add_log_action(self.request, form, "finance", "fee", True)
# return super().form_valid(form)
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# # Request user for fee creator.
# kwargs["user"] = self.request.user
# return kwargs
# def get_success_url(self):
# return reverse("finance:fee_create_done", kwargs={"pk": self.object.pk})
# class FeeCreateDoneView(LoginRequiredMixin, TemplateView):
# template_name = "finance/fee/create_done.html"
# class FeeUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
# form_class = FeeUpdateForm
# model = Fee
# success_url = reverse_lazy("finance:bill_list")
# template_name = "finance/fee/update.html"
# def form_valid(self, form):
# add_log_action(self.request, form, "finance", "fee", False)
# return super().form_valid(form)
# # Call fee if it's only yours.
# def test_func(self):
# return self.get_object().fee_creator.username == self.request.user.username
# def handle_no_permission(self):
# return redirect("finance:bill_list")
class ResolutionCreateView(LoginRequiredMixin, CreateView): class ResolutionCreateView(LoginRequiredMixin, CreateView):
form_class = ResolutionCreateForm form_class = ResolutionCreateForm
model = Resolution model = Resolution

View File

@@ -13,6 +13,8 @@ gallery_thumb_path_url = Path(settings.MEDIA_URL) / settings.GALLERY["thumb_path
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
size = (320, 320) size = (320, 320)
Image.logger.setLevel(level=logging.INFO)
def get_image_list(folder_name: str) -> list: def get_image_list(folder_name: str) -> list:
image_path = Path(gallery_path) / folder_name image_path = Path(gallery_path) / folder_name

View File

@@ -1,7 +1,9 @@
from django.contrib import admin from django.contrib import admin, messages
from django.http import HttpResponseRedirect
from .forms import RentalAdminForm, RentalItemAdminForm from .forms import RentalAdminForm, RentalItemAdminForm
from .models import Rental, RentalItem from .models import Rental, RentalItem
from .utils import generate_rental_pdf
@admin.register(Rental) @admin.register(Rental)
@@ -49,6 +51,7 @@ class RentalAdmin(admin.ModelAdmin):
{ {
"fields": ( "fields": (
"comment", "comment",
"file_field",
"status", "status",
), ),
}, },
@@ -63,8 +66,29 @@ class RentalAdmin(admin.ModelAdmin):
def change_view(self, request, object_id, form_url="", extra_context=None): def change_view(self, request, object_id, 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."
extra_context["generate_rental_pdf"] = True
return super().change_view(request, object_id, form_url, extra_context=extra_context) return super().change_view(request, object_id, form_url, extra_context=extra_context)
def response_change(self, request, obj):
if "_generate_rental_pdf" in request.POST:
if generate_rental_pdf(obj):
self.message_user(
request,
"Neues Verleihformular wurde generiert.",
messages.SUCCESS,
)
else:
self.message_user(
request,
(
"Das PDF-Dokument konnte nicht generiert werden, da der Status nicht auf "
"'Verleih genehmigt' gesetzt ist."
),
messages.WARNING,
)
return HttpResponseRedirect(".")
return super().response_change(request, obj)
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
obj.author = request.user obj.author = request.user
super().save_model(request, obj, form, change) super().save_model(request, obj, form, change)

View File

@@ -1,3 +1,4 @@
from django.core.validators import FileExtensionValidator
from django.db import models from django.db import models
from django.forms import ValidationError from django.forms import ValidationError
@@ -48,6 +49,14 @@ class Rental(models.Model):
comment = models.TextField(verbose_name="Kommentar", max_length=500, blank=True, default="") comment = models.TextField(verbose_name="Kommentar", max_length=500, blank=True, default="")
file_field = models.FileField(
upload_to="uploads/rental/rental/",
validators=[FileExtensionValidator(["pdf"])],
blank=True,
null=True,
verbose_name="Verleihformular",
)
class Status(models.TextChoices): class Status(models.TextChoices):
SUBMITTED = "S", "Eingereicht" SUBMITTED = "S", "Eingereicht"
APPROVED = "A", "Verleih genehmigt" APPROVED = "A", "Verleih genehmigt"

Binary file not shown.

66
fet2020/rental/utils.py Normal file
View File

@@ -0,0 +1,66 @@
import io
from pathlib import Path
from django.core.files import File
from pypdf import PdfReader, PdfWriter
from .models import Rental
def generate_rental_pdf(rental: Rental) -> bool:
if not rental or rental.status != Rental.Status.APPROVED:
return False
# Get data for pdf
data = {}
data.update(
{
"Vorname": rental.firstname,
"Nachname": rental.surname,
"Orga": rental.organization,
"Matrikelnummer": rental.matriculation_number,
"E-Mail": rental.email,
"Telefonnummer": rental.phone,
# Change to the correct date format
"Abholdatum": str(rental.date_start.strftime("%d.%m.%Y")),
"Rückgabedatum": str(rental.date_end.strftime("%d.%m.%Y")),
},
)
total_deposit = 0
for i, item in enumerate(rental.rentalitems.all(), start=1):
total_deposit += item.deposit
data.update(
{
f"Produkt Row{i}": item.name,
f"Menge Row{i}": "1",
f"Kaution Row{i}": item.deposit,
},
)
data.update(
{
"Gesamtkaution": total_deposit,
},
)
# Write data in pdf
pdf_path = Path(Path(__file__).parent) / "static/rental/Verleihformular.pdf"
reader = PdfReader(pdf_path)
writer = PdfWriter()
writer.append(reader)
writer.update_page_form_field_values(
writer.pages[0],
data,
)
with io.BytesIO() as bytes_stream:
writer.write(bytes_stream)
# Save pdf in rental
rental_name = f"Verleihformular-{str(rental.pk).zfill(4)}.pdf"
rental.file_field.save(rental_name, File(bytes_stream, rental_name))
return True

File diff suppressed because it is too large Load Diff

View File

@@ -7,5 +7,6 @@
<a href="{% add_preserved_filters changelist_url %}" class="closelink">{% translate 'Close' %}</a> <a href="{% add_preserved_filters changelist_url %}" class="closelink">{% translate 'Close' %}</a>
{% endif %} {% endif %}
{% if generate_pdf %}<input type="submit" value="PDF File generieren" class="default" name="_generate_pdf">{% endif %} {% if generate_pdf %}<input type="submit" value="PDF File generieren" class="default" name="_generate_pdf">{% endif %}
{% if generate_rental_pdf %}<input type="submit" value="PDF File generieren" class="default" name="_generate_rental_pdf">{% endif %}
{{ block.super }} {{ block.super }}
{% endblock submit-row %} {% endblock submit-row %}

View File

@@ -103,8 +103,12 @@
<a <a
href="{{ form.file_field.value.url }}" href="{{ form.file_field.value.url }}"
target="_blank"
class="text-gray-700 dark:text-gray-200 block w-full mt-1 rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50" class="text-gray-700 dark:text-gray-200 block w-full mt-1 rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50"
>{{ form.file_field.value }}</a> >
<i class="fa-solid fa-file fa-fw text-red-800 dark:text-red-500 md:text-inherit group-hover:text-red-800 dark:group-hover:text-red-500"></i>
<span class="ml-2 sm:ml-1">{{ object.filename }}</span>
</a>
</label> </label>
</div> </div>
{% endif %} {% endif %}
@@ -122,8 +126,12 @@
<span class="text-gray-700 dark:text-gray-200">Hochgeladene Rechnung:</span> <span class="text-gray-700 dark:text-gray-200">Hochgeladene Rechnung:</span>
<a <a
href="{{ form.file_field.value.url }}" href="{{ form.file_field.value.url }}"
target="_blank"
class="text-gray-700 dark:text-gray-200 block w-full mt-1 rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50" class="text-gray-700 dark:text-gray-200 block w-full mt-1 rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50"
>{{ form.file_field.value }}</a> >
<i class="fa-solid fa-file fa-fw text-red-800 dark:text-red-500 md:text-inherit group-hover:text-red-800 dark:group-hover:text-red-500"></i>
<span class="ml-2 sm:ml-1">{{ object.filename }}</span>
</a>
</label> </label>
</div> </div>

View File

@@ -11,7 +11,7 @@
</a> </a>
<form action="" method="GET"> <form action="" method="GET">
<div class="grid grid-cols-1 gap-x-6 gap-y-6 lg:grid-cols-6 sm:grid-cols-3 pb-6 lg:pt-0 pt-4"> <div class="grid grid-cols-1 sm:gap-x-6 gap-x-0 gap-y-6 lg:grid-cols-6 sm:grid-cols-3 pb-6 lg:pt-0 pt-4">
<button <button
id="filterDropdownButton" id="filterDropdownButton"
data-dropdown-toggle="filterDropdown" data-dropdown-toggle="filterDropdown"
@@ -51,7 +51,8 @@
name="q" name="q"
value="{{ q }}" value="{{ q }}"
placeholder="Suche" placeholder="Suche"
class="w-full" class="w-full h-full"
autofocus
> >
</div> </div>

View File

@@ -64,7 +64,7 @@
> >
<a <a
href="{% url 'rental:rentalitem_detail' elem.data.value %}" href="{% url 'rental:rentalitem_detail' elem.data.value %}"
class="text-gray-700 dark:text-gray-200" class="text-gray-700 dark:text-gray-200 underline hover:text-blue-700 dark:hover:text-blue-300"
>{{ elem.choice_label }}</a> >{{ elem.choice_label }}</a>
</label> </label>

View File

@@ -12,7 +12,7 @@
{% if object.description %} {% if object.description %}
<div class="col-span-full"> <div class="col-span-full">
<label> <label>
<h2 class="text-xl font-black text-gray-700 dark:text-gray-200">Beschreibung</h2> <h2 class="font-black text-gray-700 dark:text-gray-200">Beschreibung</h2>
<p class="text-gray-700 dark:text-gray-200">{{ object.description|safe }}</p> <p class="text-gray-700 dark:text-gray-200">{{ object.description|safe }}</p>
</label> </label>
</div> </div>