diff --git a/fet2020/rental/admin.py b/fet2020/rental/admin.py index f209feb9..42227a1d 100644 --- a/fet2020/rental/admin.py +++ b/fet2020/rental/admin.py @@ -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 .models import Rental, RentalItem +from .utils import generate_rental_pdf @admin.register(Rental) @@ -49,6 +51,7 @@ class RentalAdmin(admin.ModelAdmin): { "fields": ( "comment", + "file_field", "status", ), }, @@ -63,8 +66,29 @@ class RentalAdmin(admin.ModelAdmin): 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_rental_pdf"] = True 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): obj.author = request.user super().save_model(request, obj, form, change) diff --git a/fet2020/rental/models.py b/fet2020/rental/models.py index 34e04622..60a68c76 100644 --- a/fet2020/rental/models.py +++ b/fet2020/rental/models.py @@ -1,3 +1,4 @@ +from django.core.validators import FileExtensionValidator from django.db import models 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="") + file_field = models.FileField( + upload_to="uploads/rental/rental/", + validators=[FileExtensionValidator(["pdf"])], + blank=True, + null=True, + verbose_name="Verleihformular", + ) + class Status(models.TextChoices): SUBMITTED = "S", "Eingereicht" APPROVED = "A", "Verleih genehmigt" diff --git a/fet2020/rental/static/rental/Verleihformular.pdf b/fet2020/rental/static/rental/Verleihformular.pdf new file mode 100644 index 00000000..db8dce11 Binary files /dev/null and b/fet2020/rental/static/rental/Verleihformular.pdf differ diff --git a/fet2020/rental/utils.py b/fet2020/rental/utils.py new file mode 100644 index 00000000..4c4ff0b2 --- /dev/null +++ b/fet2020/rental/utils.py @@ -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 diff --git a/fet2020/static/css/styles.css b/fet2020/static/css/styles.css index 89091b4b..aaa52478 100644 --- a/fet2020/static/css/styles.css +++ b/fet2020/static/css/styles.css @@ -5914,6 +5914,11 @@ footer .copyright { 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 { --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)); } +.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 *) { --tw-text-opacity: 1; color: rgb(59 130 246 / var(--tw-text-opacity, 1)); diff --git a/fet2020/templates/admin/submit_line.html b/fet2020/templates/admin/submit_line.html index ec1e5bda..6c1c2c50 100644 --- a/fet2020/templates/admin/submit_line.html +++ b/fet2020/templates/admin/submit_line.html @@ -7,5 +7,6 @@ {% translate 'Close' %} {% endif %} {% if generate_pdf %}{% endif %} + {% if generate_rental_pdf %}{% endif %} {{ block.super }} {% endblock submit-row %} diff --git a/fet2020/templates/rental/create.html b/fet2020/templates/rental/create.html index 92f94592..1c95a97a 100644 --- a/fet2020/templates/rental/create.html +++ b/fet2020/templates/rental/create.html @@ -64,7 +64,7 @@ > {{ elem.choice_label }} diff --git a/fet2020/templates/rental/rentalitem_detail.html b/fet2020/templates/rental/rentalitem_detail.html index 9f306f61..d49a0761 100644 --- a/fet2020/templates/rental/rentalitem_detail.html +++ b/fet2020/templates/rental/rentalitem_detail.html @@ -12,7 +12,7 @@ {% if object.description %}