Compare commits
6 Commits
ead98785de
...
7b78368eb0
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b78368eb0 | |||
| 8939fe5776 | |||
| 96b2549503 | |||
| 60f231d908 | |||
| 42b80bd143 | |||
| 15e8ffc3c8 |
@@ -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)
|
||||
class ResolutionAdmin(admin.ModelAdmin):
|
||||
form = ResolutionAdminForm
|
||||
|
||||
@@ -283,171 +283,6 @@ class BillUpdateForm(forms.ModelForm):
|
||||
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 Meta:
|
||||
model = Resolution
|
||||
@@ -603,28 +438,6 @@ class BillAdminForm(forms.ModelForm):
|
||||
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):
|
||||
total = forms.CharField()
|
||||
budget_remaining = forms.CharField()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from pathlib import Path
|
||||
|
||||
from django.core.validators import FileExtensionValidator, ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
@@ -38,71 +40,6 @@ class BankData(models.Model):
|
||||
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):
|
||||
id = models.CharField(primary_key=True, max_length=128, verbose_name="Beschlussnummer")
|
||||
name = models.CharField(max_length=128, verbose_name="Bezeichnung")
|
||||
@@ -286,3 +223,6 @@ class Bill(models.Model):
|
||||
def clean(self):
|
||||
if self.status is None:
|
||||
self.status = Bill.Status.SUBMITTED
|
||||
|
||||
def filename(self):
|
||||
return Path(self.file_field.name).name
|
||||
|
||||
@@ -24,14 +24,6 @@ urlpatterns = [
|
||||
BillCreateDoneView.as_view(),
|
||||
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
|
||||
path("create-resolution/", ResolutionCreateView.as_view(), name="resolution_create"),
|
||||
path("resolutions/", ResolutionListView.as_view(), name="resolution_list"),
|
||||
|
||||
@@ -80,58 +80,3 @@ def generate_pdf(wiref):
|
||||
wiref.file_field.save(wiref_name, File(bytes_stream, wiref_name))
|
||||
|
||||
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
|
||||
|
||||
@@ -89,26 +89,17 @@ class BillListView(LoginRequiredMixin, ListView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
# context["fee_status"] = Fee.Status
|
||||
context["bill_status"] = Bill.Status
|
||||
|
||||
return context
|
||||
|
||||
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 = (
|
||||
Bill.objects.filter(bill_creator__username=self.request.user)
|
||||
.values("amount", "status", "id", "date", "purpose")
|
||||
.annotate(model=Value("BILL", output_field=CharField()))
|
||||
)
|
||||
|
||||
# qs = qs1.union(qs2, all=True)
|
||||
return qs.order_by("-date", "purpose")
|
||||
|
||||
|
||||
@@ -146,57 +137,6 @@ class BillUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
|
||||
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):
|
||||
form_class = ResolutionCreateForm
|
||||
model = Resolution
|
||||
|
||||
@@ -13,6 +13,8 @@ gallery_thumb_path_url = Path(settings.MEDIA_URL) / settings.GALLERY["thumb_path
|
||||
logger = logging.getLogger(__name__)
|
||||
size = (320, 320)
|
||||
|
||||
Image.logger.setLevel(level=logging.INFO)
|
||||
|
||||
|
||||
def get_image_list(folder_name: str) -> list:
|
||||
image_path = Path(gallery_path) / folder_name
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
BIN
fet2020/rental/static/rental/Verleihformular.pdf
Normal file
BIN
fet2020/rental/static/rental/Verleihformular.pdf
Normal file
Binary file not shown.
66
fet2020/rental/utils.py
Normal file
66
fet2020/rental/utils.py
Normal 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
@@ -7,5 +7,6 @@
|
||||
<a href="{% add_preserved_filters changelist_url %}" class="closelink">{% translate 'Close' %}</a>
|
||||
{% 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 }}
|
||||
{% endblock submit-row %}
|
||||
|
||||
@@ -103,8 +103,12 @@
|
||||
|
||||
<a
|
||||
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"
|
||||
>{{ 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>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -122,8 +126,12 @@
|
||||
<span class="text-gray-700 dark:text-gray-200">Hochgeladene Rechnung:</span>
|
||||
<a
|
||||
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"
|
||||
>{{ 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>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</a>
|
||||
|
||||
<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
|
||||
id="filterDropdownButton"
|
||||
data-dropdown-toggle="filterDropdown"
|
||||
@@ -51,10 +51,11 @@
|
||||
name="q"
|
||||
value="{{ q }}"
|
||||
placeholder="Suche"
|
||||
class="w-full"
|
||||
class="w-full h-full"
|
||||
autofocus
|
||||
>
|
||||
</div>
|
||||
|
||||
|
||||
<button type="submit" class="block btn btn-primary" name="" value="Submit">Anwenden</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
>
|
||||
<a
|
||||
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>
|
||||
</label>
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
{% if object.description %}
|
||||
<div class="col-span-full">
|
||||
<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>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user