add Verleihformular

This commit is contained in:
2025-07-16 19:21:47 +02:00
parent 15e8ffc3c8
commit 42b80bd143
8 changed files with 113 additions and 3 deletions

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

View File

@@ -5914,6 +5914,11 @@ footer .copyright {
color: rgb(37 99 235 / var(--tw-text-opacity, 1)); color: rgb(37 99 235 / var(--tw-text-opacity, 1));
} }
.hover\:text-blue-700:hover {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity, 1));
}
.hover\:text-gray-600:hover { .hover\:text-gray-600:hover {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(75 85 99 / var(--tw-text-opacity, 1)); color: rgb(75 85 99 / var(--tw-text-opacity, 1));
@@ -6337,6 +6342,11 @@ footer .copyright {
background-color: rgb(8 47 73 / var(--tw-bg-opacity, 1)); background-color: rgb(8 47 73 / var(--tw-bg-opacity, 1));
} }
.dark\:hover\:text-blue-300:hover:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(147 197 253 / var(--tw-text-opacity, 1));
}
.dark\:hover\:text-blue-500:hover:is(.dark *) { .dark\:hover\:text-blue-500:hover:is(.dark *) {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(59 130 246 / var(--tw-text-opacity, 1)); color: rgb(59 130 246 / var(--tw-text-opacity, 1));

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

@@ -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>