From 9ad8a72acaa291e1464e5e41c27a6c62c2ceb14f Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 08:55:26 +0200 Subject: [PATCH 01/23] init --- .../coop/templates/coop/user_profile_pdf.html | 84 +++++++++++++++++++ tapir/coop/urls.py | 5 ++ tapir/coop/views/shareowner.py | 44 +++++++++- 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 tapir/coop/templates/coop/user_profile_pdf.html diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html new file mode 100644 index 000000000..66ebed040 --- /dev/null +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -0,0 +1,84 @@ + +{% load static %} +{% load django_bootstrap5 %} +{% load accounts %} +{% load utils %} + + + + Mitgliedsprofil - {{ person.get_display_name }} + + +
+

Stammdaten

+
+
Name
+
+ {{ person.first_name }} {{ person.last_name }} +
+
E‑Mail
+
+ {{ person.email }} +
+
Telefon
+
+ {{ person.phone_number }} +
+
Geburtsdatum
+
+ {% if person.birthdate %} + {{ person.birthdate|date:"Y-m-d" }} + {% else %} + - + {% endif %} +
+
Adresse
+
+ {{ person.get_display_address }} +
+
Sprache
+
+ {{ person.get_preferred_language_display }} +
+
+
+
+

Schichten

+ {% if attendances %} + + + + + + + + + + {% for att in attendances %} + + + + + + {% endfor %} + +
DatumBezeichnungState
+ {% if att.slot and att.slot.shift and att.slot.shift.start_time %} + {{ att.slot.shift.start_time|date:"Y-m-d H-i" }} + {% else %} + - + {% endif %} + + {% if att.slot and att.slot.shift %} + {{ att.slot.shift.title|default:att.slot.name|default:"(ohne Bezeichnung)" }} + {% else %} + (Slot entfernt) + {% endif %} + {{ att.get_state_display }}
+ {% else %} +
Keine abgeschlossenen Schichten gefunden.
+ {% endif %} +
+
Generiert am {{ generated_at|date:"Y-m-d H:i" }}
+ + diff --git a/tapir/coop/urls.py b/tapir/coop/urls.py index d554cc392..0444981fc 100644 --- a/tapir/coop/urls.py +++ b/tapir/coop/urls.py @@ -255,4 +255,9 @@ views.MemberSelfRegisterApiView.as_view(), name="member_self_register", ), + path( + "member//profile_pdf", + views.UserProfilePDFView.as_view(), + name="user_profile_pdf", + ), ] diff --git a/tapir/coop/views/shareowner.py b/tapir/coop/views/shareowner.py index a9e330546..cbddd4d50 100644 --- a/tapir/coop/views/shareowner.py +++ b/tapir/coop/views/shareowner.py @@ -4,6 +4,7 @@ import django_filters import django_tables2 +import weasyprint from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required @@ -18,7 +19,7 @@ HttpResponseRedirect, ) from django.shortcuts import get_object_or_404, redirect -from django.template import Context, Template +from django.template import Context, Template, loader from django.utils import timezone from django.utils.translation import gettext_lazy as _ from django.utils.translation import pgettext_lazy @@ -1105,3 +1106,44 @@ def get_context_data(self, **kwargs): def get_success_url(self): return self.get_share_owner().get_absolute_url() + + +class UserProfilePDFView(generic.DetailView): + model = ShareOwner + pk_url_kwarg = "user_id" + template_name = "coop/user_profile_pdf.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + shareowner = self.object + person = getattr(shareowner, "user", None) or shareowner + + attendances = [] + if shareowner.user_id and shareowner.user is not None: + attendances = shareowner.user.shift_attesndances.select_related( + "slot", "slot__shift" + ).order_by("slot__shift__start_time") + + context.update( + { + "person": person, + "attendances": attendances, + "generated_at": timezone.now(), + } + ) + return context + + def render_to_response(self, context, **response_kwargs): + request = self.request + html_string = loader.render_to_string( + self.template_name, context, request=request + ) + html = weasyprint.HTML( + string=html_string, base_url=request.build_absolute_uri("/") + ) + pdf = html.write_pdf() + + response = HttpResponse(pdf, content_type="application/pdf") + filename = f"user-{self.object.pk}-profile.pdf" + response["Content-Disposition"] = f'inline; filename="{filename}"' + return response From 2ab505e80b81eb64e46e35addbe5fa3aec5afa61 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 09:17:38 +0200 Subject: [PATCH 02/23] include button --- .../coop/tags/user_coop_share_ownership_list_tag.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tapir/coop/templates/coop/tags/user_coop_share_ownership_list_tag.html b/tapir/coop/templates/coop/tags/user_coop_share_ownership_list_tag.html index 7340e7a33..4bf5a2b96 100644 --- a/tapir/coop/templates/coop/tags/user_coop_share_ownership_list_tag.html +++ b/tapir/coop/templates/coop/tags/user_coop_share_ownership_list_tag.html @@ -12,6 +12,10 @@
+ + picture_as_pdf{% translate 'Summary' %} + file_present{% translate 'Membership confirmation' %} From 93e99e1e2ffe32af8aa44d49064c414b53e9279d Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 09:17:56 +0200 Subject: [PATCH 03/23] pk --- tapir/coop/urls.py | 2 +- tapir/coop/views/shareowner.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tapir/coop/urls.py b/tapir/coop/urls.py index 0444981fc..134127cb4 100644 --- a/tapir/coop/urls.py +++ b/tapir/coop/urls.py @@ -256,7 +256,7 @@ name="member_self_register", ), path( - "member//profile_pdf", + "member//profile_pdf", views.UserProfilePDFView.as_view(), name="user_profile_pdf", ), diff --git a/tapir/coop/views/shareowner.py b/tapir/coop/views/shareowner.py index cbddd4d50..788c2f795 100644 --- a/tapir/coop/views/shareowner.py +++ b/tapir/coop/views/shareowner.py @@ -1110,7 +1110,7 @@ def get_success_url(self): class UserProfilePDFView(generic.DetailView): model = ShareOwner - pk_url_kwarg = "user_id" + pk_url_kwarg = "pk" template_name = "coop/user_profile_pdf.html" def get_context_data(self, **kwargs): @@ -1119,8 +1119,8 @@ def get_context_data(self, **kwargs): person = getattr(shareowner, "user", None) or shareowner attendances = [] - if shareowner.user_id and shareowner.user is not None: - attendances = shareowner.user.shift_attesndances.select_related( + if shareowner.pk and shareowner.user is not None: + attendances = shareowner.user.shift_attendances.select_related( "slot", "slot__shift" ).order_by("slot__shift__start_time") From e9a449bffb7fe95e9421f53933a62f7cb4ae7860 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 09:21:02 +0200 Subject: [PATCH 04/23] style --- .../coop/templates/coop/user_profile_pdf.html | 248 +++++++++++++----- 1 file changed, 180 insertions(+), 68 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 66ebed040..6dd63d905 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -6,79 +6,191 @@ + Mitgliedsprofil - {{ person.get_display_name }} + -
-

Stammdaten

-
-
Name
-
- {{ person.first_name }} {{ person.last_name }} -
-
E‑Mail
-
- {{ person.email }} -
-
Telefon
-
- {{ person.phone_number }} -
-
Geburtsdatum
-
- {% if person.birthdate %} - {{ person.birthdate|date:"Y-m-d" }} - {% else %} - - - {% endif %} -
-
Adresse
-
- {{ person.get_display_address }} -
-
Sprache
-
- {{ person.get_preferred_language_display }} -
-
-
-
-

Schichten

- {% if attendances %} - - - - - - - - - - {% for att in attendances %} +
+

Mitgliedsprofil: {{ person.get_display_name }}

+ +
+

Stammdaten

+
+
Name
+
+ {{ person.first_name }} {{ person.last_name }} +
+
E‑Mail
+
+ {% if person.email %} + {{ person.email }} + {% else %} + - + {% endif %} +
+
Telefon
+
+ {% if person.phone_number %} + {{ person.phone_number }} + {% else %} + - + {% endif %} +
+
Geburtsdatum
+
+ {{ person.birthdate|date:"j. F Y"|default:"-" }} +
+
Adresse
+
+ {{ person.get_display_address|default:"-" }} +
+
Sprache
+
+ {{ person.get_preferred_language_display }} +
+
+
+ +
+

Schichten

+ {% if attendances %} +
DatumBezeichnungState
+ - - - + + + - {% endfor %} - -
- {% if att.slot and att.slot.shift and att.slot.shift.start_time %} - {{ att.slot.shift.start_time|date:"Y-m-d H-i" }} - {% else %} - - - {% endif %} - - {% if att.slot and att.slot.shift %} - {{ att.slot.shift.title|default:att.slot.name|default:"(ohne Bezeichnung)" }} - {% else %} - (Slot entfernt) - {% endif %} - {{ att.get_state_display }}Datum & UhrzeitBezeichnungStatus
- {% else %} -
Keine abgeschlossenen Schichten gefunden.
- {% endif %} + + + {% for att in attendances %} + + + {% if att.slot.shift.start_time %} + {{ att.slot.shift.start_time|date:"d.m.Y H:i" }} + {% else %} + - + {% endif %} + + + {% if att.slot.shift %} + {{ att.slot.shift.title|default:att.slot.name|default:"(ohne Bezeichnung)" }} + {% else %} + (Slot entfernt) + {% endif %} + + {{ att.get_state_display }} + + {% endfor %} + + + {% else %} +
Keine abgeschlossenen Schichten gefunden.
+ {% endif %} +
+ -
Generiert am {{ generated_at|date:"Y-m-d H:i" }}
From ce367ebdf102bdc6f692096a24894f2ad22bec8c Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 09:46:07 +0200 Subject: [PATCH 05/23] print shareowner name --- .../membership_confirmation_pdf.default.html | 2 +- .../coop/templates/coop/user_profile_pdf.html | 193 +++++++++--------- tapir/coop/views/shareowner.py | 1 + 3 files changed, 98 insertions(+), 98 deletions(-) diff --git a/tapir/coop/templates/coop/pdf/membership_confirmation_pdf.default.html b/tapir/coop/templates/coop/pdf/membership_confirmation_pdf.default.html index 06b668811..3573b7283 100644 --- a/tapir/coop/templates/coop/pdf/membership_confirmation_pdf.default.html +++ b/tapir/coop/templates/coop/pdf/membership_confirmation_pdf.default.html @@ -1,8 +1,8 @@ + {% load static %} {% load django_bootstrap5 %} {% load i18n %} {% load utils %} - diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 6dd63d905..0be23bd3c 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -2,12 +2,13 @@ {% load static %} {% load django_bootstrap5 %} {% load accounts %} +{% load i18n %} {% load utils %} - + - Mitgliedsprofil - {{ person.get_display_name }} + {% translate "Member Profile" %}: {% get_display_name_full shareowner %} - - -
-

Mitgliedsprofil: {{ person.get_display_name }}

- -
-

Stammdaten

-
-
Name
-
- {{ person.first_name }} {{ person.last_name }} -
-
E‑Mail
-
- {% if person.email %} - {{ person.email }} - {% else %} - - - {% endif %} -
-
Telefon
-
- {% if person.phone_number %} - {{ person.phone_number }} - {% else %} - - - {% endif %} -
-
Geburtsdatum
-
- {{ person.birthdate|date:"j. F Y"|default:"-" }} -
-
Adresse
-
- {{ person.get_display_address|default:"-" }} -
-
Sprache
-
- {{ person.get_preferred_language_display }} -
-
-
- -
-

Schichten

- {% if attendances %} - - - - - - - - - - {% for att in attendances %} - - - - - - {% endfor %} - -
Datum & UhrzeitBezeichnungStatus
- {% if att.slot.shift.start_time %} - {{ att.slot.shift.start_time|date:"d.m.Y H:i" }} - {% else %} - - - {% endif %} - - {% if att.slot.shift %} - {{ att.slot.shift.title|default:att.slot.name|default:"(ohne Bezeichnung)" }} - {% else %} - (Slot entfernt) - {% endif %} - {{ att.get_state_display }}
- {% else %} -
Keine abgeschlossenen Schichten gefunden.
- {% endif %} -
- -
- + + + +
+

{% translate "Member Profile" %}: {% get_display_name_full shareowner %}

+
+

{% translate "Personal Information" %}

+
+
{% translate "Name" %}
+
+{{ person.first_name }} {{ person.last_name }} +
+
{% translate "Email" %}
+
+{% if person.email %} +{{ person.email }} +{% else %} +- +{% endif %} +
+
{% translate "Phone" %}
+
+{% if person.phone_number %} +{{ person.phone_number }} +{% else %} +- +{% endif %} +
+
{% translate "Date of Birth" %}
+
+{{ person.birthdate|date:"j. F Y"|default:"-" }} +
+
{% translate "Address" %}
+
+{{ person.get_display_address|default:"-" }} +
+
{% translate "Language" %}
+
+{{ person.get_preferred_language_display }} +
+
+
+
+

{% translate "Shifts" %}

+{% if attendances %} + + + + + + + + + +{% for att in attendances %} + + + + + +{% endfor %} + +
{% translate "Date & Time" %}{% translate "Description" %}{% translate "Status" %}
+{% if att.slot.shift.start_time %} +{{ att.slot.shift.start_time|date:"d.m.Y H:i" }} +{% else %} +- +{% endif %} + +{% if att.slot.shift %} +{{ att.slot.shift.title|default:att.slot.name|default:"(no description)" }} +{% else %} +{% translate "(Slot removed)" %} +{% endif %} +{{ att.get_state_display }}
+{% else %} +
{% translate "No completed shifts found." %}
+{% endif %} +
+ +
+ diff --git a/tapir/coop/views/shareowner.py b/tapir/coop/views/shareowner.py index 788c2f795..8530e8962 100644 --- a/tapir/coop/views/shareowner.py +++ b/tapir/coop/views/shareowner.py @@ -1128,6 +1128,7 @@ def get_context_data(self, **kwargs): { "person": person, "attendances": attendances, + "shareowner": shareowner, "generated_at": timezone.now(), } ) From 360e2e7e7be6f6c046edeca8a66e8eda9d27552c Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 09:49:32 +0200 Subject: [PATCH 06/23] simpler design --- .../coop/templates/coop/user_profile_pdf.html | 264 +++++++----------- 1 file changed, 103 insertions(+), 161 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 0be23bd3c..83909bacd 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -1,7 +1,6 @@ {% load static %} {% load django_bootstrap5 %} -{% load accounts %} {% load i18n %} {% load utils %} @@ -9,187 +8,130 @@ {% translate "Member Profile" %}: {% get_display_name_full shareowner %} + - - -
-

{% translate "Member Profile" %}: {% get_display_name_full shareowner %}

-
-

{% translate "Personal Information" %}

-
-
{% translate "Name" %}
-
-{{ person.first_name }} {{ person.last_name }} -
-
{% translate "Email" %}
-
-{% if person.email %} -{{ person.email }} -{% else %} -- -{% endif %} -
-
{% translate "Phone" %}
-
-{% if person.phone_number %} -{{ person.phone_number }} -{% else %} -- -{% endif %} -
-
{% translate "Date of Birth" %}
-
-{{ person.birthdate|date:"j. F Y"|default:"-" }} -
-
{% translate "Address" %}
-
-{{ person.get_display_address|default:"-" }} -
-
{% translate "Language" %}
-
-{{ person.get_preferred_language_display }} -
-
-
-
-

{% translate "Shifts" %}

-{% if attendances %} - - - - - - - - - -{% for att in attendances %} - - - - - -{% endfor %} - -
{% translate "Date & Time" %}{% translate "Description" %}{% translate "Status" %}
-{% if att.slot.shift.start_time %} -{{ att.slot.shift.start_time|date:"d.m.Y H:i" }} -{% else %} -- -{% endif %} - -{% if att.slot.shift %} -{{ att.slot.shift.title|default:att.slot.name|default:"(no description)" }} -{% else %} -{% translate "(Slot removed)" %} -{% endif %} -{{ att.get_state_display }}
-{% else %} -
{% translate "No completed shifts found." %}
-{% endif %} -
- -
- + + + +

{% translate "Member Profile" %}: {% get_display_name_full shareowner %}

+
+

{% translate "Personal Information" %}

+
+
{% translate "Name" %}
+
+ {{ person.first_name }} {{ person.last_name }} +
+
{% translate "Email" %}
+
+ {% if person.email %} + {{ person.email }} + {% else %} + - + {% endif %} +
+
{% translate "Phone" %}
+
+ {% if person.phone_number %} + {{ person.phone_number }} + {% else %} + - + {% endif %} +
+
{% translate "Date of Birth" %}
+
+ {{ person.birthdate|date:"j. F Y"|default:"-" }} +
+
{% translate "Address" %}
+
+ {{ person.get_display_address|default:"-" }} +
+
{% translate "Language" %}
+
+ {{ person.get_preferred_language_display }} +
+
+
+
+

{% translate "Shifts" %}

+ {% if attendances %} + + + + + + + + + + {% for att in attendances %} + + + + + + {% endfor %} + +
{% translate "Date & Time" %}{% translate "Description" %}{% translate "Status" %}
+ {% if att.slot.shift.start_time %} + {{ att.slot.shift.start_time|date:"d.m.Y H:i" }} + {% else %} + - + {% endif %} + + {% if att.slot.shift %} + {{ att.slot.shift.title|default:att.slot.name|default:"(no description)" }} + {% else %} + {% translate "(Slot removed)" %} + {% endif %} + {{ att.get_state_display }}
+ {% else %} +
{% translate "No completed shifts found." %}
+ {% endif %} +
+ + From 33675beb850f7d44b556354fe132a222bdc611c4 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 09:57:10 +0200 Subject: [PATCH 07/23] translation --- .../coop/templates/coop/user_profile_pdf.html | 2 +- .../locale/de/LC_MESSAGES/django.po | 169 ++++++++++++------ 2 files changed, 112 insertions(+), 59 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 83909bacd..b2324323e 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -59,7 +59,7 @@

{% translate "Member Profile" %}: {% get_display_name_full shareowner %}

-

{% translate "Personal Information" %}

+

{% translate "Personal Data" %}

{% translate "Name" %}
diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po index 0e17400fd..d56126666 100644 --- a/tapir/translations/locale/de/LC_MESSAGES/django.po +++ b/tapir/translations/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-06 20:45+0200\n" +"POT-Creation-Date: 2026-07-12 09:54+0200\n" "PO-Revision-Date: 2025-07-07 13:06+0000\n" "Last-Translator: Weblate Admin \n" "Language-Team: German \n" @@ -289,8 +289,8 @@ msgid "I agree that my membership card will be scanned at the checkout when I ma msgstr "Ich bin damit einverstanden, dass meine Mitgliedskarte beim Einkauf an der Kasse gescannt und somit mein Einkauf erfasst und gespeichert wird:" #: accounts/templates/accounts/purchase_tracking_card.html:30 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:176 #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:180 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:184 msgid "Yes,No" msgstr "Ja, Nein" @@ -316,6 +316,7 @@ msgstr "Mitglied" #: accounts/templates/accounts/user_detail.html:27 #: coop/templates/coop/shareowner_detail.html:17 +#: coop/templates/coop/user_profile_pdf.html:62 msgid "Personal Data" msgstr "Persönliche Daten" @@ -337,9 +338,9 @@ msgstr "Benutzername bearbeiten" #: coop/templates/coop/draftuser_detail.html:238 #: coop/templates/coop/membershipresignation_detail.html:107 #: coop/templates/coop/shareowner_detail.html:30 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:22 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:100 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:121 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:26 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:104 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:125 #: core/templates/core/featureflag_list.html:30 #: shifts/templates/shifts/shift_detail.html:65 #: shifts/templates/shifts/shift_template_detail.html:29 @@ -355,7 +356,8 @@ msgstr "Name und Pronomen bearbeiten" #: accounts/templates/accounts/user_detail.html:59 #: coop/templates/coop/draftuser_detail.html:70 #: coop/templates/coop/draftuser_detail.html:130 -#: coop/templates/coop/shareowner_detail.html:43 coop/views/draftuser.py:260 +#: coop/templates/coop/shareowner_detail.html:43 +#: coop/templates/coop/user_profile_pdf.html:64 coop/views/draftuser.py:260 #: core/templates/core/email_list.html:38 #: core/templates/core/featureflag_list.html:18 #: financingcampaign/templates/financingcampaign/general.html:25 @@ -372,6 +374,7 @@ msgstr "Nutzer*innenname" #: coop/templates/coop/draftuser_detail.html:73 #: coop/templates/coop/draftuser_detail.html:138 #: coop/templates/coop/shareowner_detail.html:47 +#: coop/templates/coop/user_profile_pdf.html:68 msgid "Email" msgstr "E-Mail-Adresse" @@ -391,6 +394,7 @@ msgstr "Fehlend" #: coop/templates/coop/draftuser_detail.html:72 #: coop/templates/coop/draftuser_detail.html:156 #: coop/templates/coop/shareowner_detail.html:65 +#: coop/templates/coop/user_profile_pdf.html:88 msgid "Address" msgstr "Adresse" @@ -530,8 +534,8 @@ msgstr "Schickt mir eine Anleitung!" msgid "Enter a valid username. This value may contain only letters, numbers, and ./-/_ characters." msgstr "Der angegebene Name ist ungültig. Er darf nur Buchstaben, Zahlen und die Symbole ./-/_ enthalten." -#: accounts/views.py:129 accounts/views.py:134 coop/views/shareowner.py:285 -#: coop/views/shareowner.py:290 +#: accounts/views.py:129 accounts/views.py:134 coop/views/shareowner.py:286 +#: coop/views/shareowner.py:291 #, python-format msgid "Edit member: %(name)s" msgstr "Mitglied bearbeiten: %(name)s" @@ -783,8 +787,8 @@ msgstr "Ist investierendes Mitglied" #: coop/models.py:90 coop/models.py:476 #: coop/templates/coop/draftuser_detail.html:176 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:48 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:175 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:52 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:179 msgid "Ratenzahlung" msgstr "Ratenzahlung" @@ -813,7 +817,7 @@ msgid "Investing" msgstr "Investierend" #: coop/models.py:369 coop/templates/coop/draftuser_detail.html:171 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:111 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:115 #: coop/views/statistics.py:135 msgid "Active" msgstr "Aktiv" @@ -958,7 +962,7 @@ msgstr "Löschen bestätigen" #: coop/templates/coop/confirm_delete_incoming_payment.html:31 #: coop/templates/coop/confirm_delete_share_ownership.html:24 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:135 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:139 #: financingcampaign/templates/financingcampaign/confirm_delete.html:24 #: shifts/templates/shifts/shift_confirm_delete.html:30 msgid "Delete" @@ -1020,9 +1024,9 @@ msgid "List of similar members" msgstr "Liste ähnlicher Mitglieder" #: coop/templates/coop/draftuser_detail.html:69 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:31 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:98 -#: coop/views/shareowner.py:611 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:35 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:102 +#: coop/templates/coop/user_profile_pdf.html:106 coop/views/shareowner.py:612 #: shifts/templates/shifts/user_shifts_overview_tag.html:26 msgid "Status" msgstr "Status" @@ -1045,7 +1049,7 @@ msgid "Shares requested" msgstr "Angeforderte Anteile" #: coop/templates/coop/draftuser_detail.html:190 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:53 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:57 #: shifts/models.py:45 msgid "Welcome Session" msgstr "Willkommenstreffen" @@ -2022,7 +2026,7 @@ msgstr "Dein Konto in Tapir, das Mitgliedersystem von %(coop_name)s" #: coop/templates/coop/extra_share_request.html:7 #: coop/templates/coop/extra_share_request.html:17 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:84 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:88 msgid "Buy more shares" msgstr "Weitere Anteile zeichnen" @@ -2101,7 +2105,7 @@ msgid "General Tapir Accounts" msgstr "Allgemeine Tapir-Konten" #: coop/templates/coop/incoming_payment_list.html:10 -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:168 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:172 msgid "Payments" msgstr "Zahlungen" @@ -2488,10 +2492,14 @@ msgstr "" " " #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:17 +msgid "Summary" +msgstr "Zusammenfassung" + +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:21 msgid "Membership confirmation" msgstr "Mitgliedsbestätigung" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:35 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:39 #, fuzzy, python-format #| msgid "" #| "\n" @@ -2506,7 +2514,7 @@ msgstr "" " Mitglied #%(coop_share_owner_id)s\n" " " -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:40 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:44 #, fuzzy, python-format #| msgid "" #| "\n" @@ -2521,7 +2529,7 @@ msgstr "" " Mitglied #%(coop_share_owner_id)s\n" " " -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:56 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:60 #: shifts/models.py:933 shifts/templates/shifts/shift_day_printable.html:214 #: shifts/templates/shifts/shift_day_printable.html:276 #: shifts/templates/shifts/shift_detail.html:304 @@ -2529,36 +2537,36 @@ msgstr "" msgid "Attended" msgstr "Teilgenommen" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:58 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:62 #: shifts/models.py:932 msgid "Pending" msgstr "Ausstehend" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:65 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:69 msgid "Mark Attended" msgstr "Als teilgenommen markieren" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:74 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:78 msgid "Owned shares" msgstr "Anteile" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:92 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:96 msgid "List of shares owned by this member" msgstr "Liste der Anteile die dieses Mitglied gehören" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:96 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:100 msgid "Starts at" msgstr "Anfangsdatum" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:97 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:101 msgid "Ends at" msgstr "Endet am" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:113 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:117 msgid "Sold or future" msgstr "" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:138 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:142 msgid "" "\n" " Only use this to correct mistakes, i.e. if the share was\n" @@ -2572,22 +2580,76 @@ msgstr "" "Bitte nur verwenden, wenn ein tatsächlicher Fehler vorliegt, z.B. ein Anteil eingetragen wurde, der nie gekauft wurde. Wenn die Person ihren Anteil einfach an den Coop zurückverkauft hat, markiere den Anteil bitte als 'verkauft'.\n" " " -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:161 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:165 msgid "Add Shares" msgstr "Anteile hinzufügen" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:179 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:183 msgid "Willing to gift a share" msgstr "Bereit Anteile zu schenken" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:189 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:193 msgid "Send membership confirmation email" msgstr "Mitgliedsbestätigung per Mail senden" -#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:195 +#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:199 msgid "User is not a cooperative member." msgstr "Benutzer*in ist kein Genossenschaftsmitglied." +#: coop/templates/coop/user_profile_pdf.html:10 +#: coop/templates/coop/user_profile_pdf.html:60 +msgid "Member Profile" +msgstr "Mitgliederprofil" + +#: coop/templates/coop/user_profile_pdf.html:76 +msgid "Phone" +msgstr "" + +#: coop/templates/coop/user_profile_pdf.html:84 +msgid "Date of Birth" +msgstr "" + +#: coop/templates/coop/user_profile_pdf.html:92 +#, fuzzy +#| msgid "Preferred Language" +msgid "Language" +msgstr "Bevorzugte Sprache" + +#: coop/templates/coop/user_profile_pdf.html:99 shifts/apps.py:36 +#: shifts/templates/shifts/user_shifts_overview_tag.html:8 +msgid "Shifts" +msgstr "Schichten" + +#: coop/templates/coop/user_profile_pdf.html:104 +msgid "Date & Time" +msgstr "" + +#: coop/templates/coop/user_profile_pdf.html:105 +#: core/templates/core/email_list.html:39 shifts/models.py:502 +#: shifts/models.py:1071 shifts/templates/shifts/user_shift_account_log.html:29 +msgid "Description" +msgstr "Beschreibung" + +#: coop/templates/coop/user_profile_pdf.html:123 +msgid "(Slot removed)" +msgstr "" + +#: coop/templates/coop/user_profile_pdf.html:132 +#, fuzzy +#| msgid "" +#| "\n" +#| " You completed your shift\n" +msgid "No completed shifts found." +msgstr "" +"\n" +"Du hast deine Schicht beendet.\n" + +#: coop/templates/coop/user_profile_pdf.html:135 +#, fuzzy +#| msgid "Generated from" +msgid "Generated on" +msgstr "Erzeugt von" + #: coop/views/draftuser.py:89 coop/views/draftuser.py:94 #, python-format msgid "Edit applicant: %(name)s" @@ -2664,71 +2726,71 @@ msgstr "Auszahlungsende" msgid "Cancel membership of %(name)s" msgstr "Beende Mitgliedschaft von %(name)s" -#: coop/views/shareowner.py:146 coop/views/shareowner.py:151 +#: coop/views/shareowner.py:147 coop/views/shareowner.py:152 #, python-format msgid "Edit share: %(name)s" msgstr "Anteil bearbeiten: %(name)s" -#: coop/views/shareowner.py:171 coop/views/shareowner.py:176 +#: coop/views/shareowner.py:172 coop/views/shareowner.py:177 #, python-format msgid "Add shares to %(name)s" msgstr "Anteile zu %(name)s hinzufügen" -#: coop/views/shareowner.py:390 +#: coop/views/shareowner.py:391 msgid "Membership confirmation email sent." msgstr "Mitgliedsbestätigung per Mail gesendet." -#: coop/views/shareowner.py:612 shifts/templates/shifts/shift_filters.html:45 +#: coop/views/shareowner.py:613 shifts/templates/shifts/shift_filters.html:45 msgid "Any" msgstr "Alle" -#: coop/views/shareowner.py:617 +#: coop/views/shareowner.py:618 #: shifts/templates/shifts/user_shifts_overview_tag.html:79 msgid "Shift Status" msgstr "Schichtstatus" -#: coop/views/shareowner.py:625 +#: coop/views/shareowner.py:626 msgid "Is registered to an ABCD-slot that requires a qualification" msgstr "Ist für eine ABCD-Schicht eingetragen, die Qualifikation erfordert" -#: coop/views/shareowner.py:633 +#: coop/views/shareowner.py:634 msgid "Is registered to a slot that requires a qualification" msgstr "Ist für eine Schicht eingetragen, die Qualifikation erfordert" -#: coop/views/shareowner.py:641 +#: coop/views/shareowner.py:642 msgid "Has qualification" msgstr "Hat Qualifikation" -#: coop/views/shareowner.py:649 +#: coop/views/shareowner.py:650 msgid "Does not have qualification" msgstr "Hat die Qualifikation nicht" -#: coop/views/shareowner.py:656 shifts/forms.py:788 +#: coop/views/shareowner.py:657 shifts/forms.py:788 msgid "ABCD Week" msgstr "ABCD-Woche" -#: coop/views/shareowner.py:659 +#: coop/views/shareowner.py:660 msgid "Is fully paid" msgstr "Hat vollständig bezahlt" -#: coop/views/shareowner.py:662 +#: coop/views/shareowner.py:663 msgid "Name or member ID" msgstr "Name oder Mitgliedsnummer" -#: coop/views/shareowner.py:666 +#: coop/views/shareowner.py:667 msgid "Is currently exempted from shifts" msgstr "Ist derzeit von der Schichtarbeit befreit" -#: coop/views/shareowner.py:671 +#: coop/views/shareowner.py:672 msgid "Shift Name" msgstr "Schichtname" -#: coop/views/shareowner.py:987 +#: coop/views/shareowner.py:988 msgctxt "Willing to give a share" msgid "No" msgstr "Nein" -#: coop/views/shareowner.py:1092 +#: coop/views/shareowner.py:1093 msgid "Thank you for signing additional shares, we truly appreciate your contribution and commitment! You will receive an email confirmation soon." msgstr "Vielen Dank für das Zeichnen weiterer Anteile, wir freuen und bedanken uns! Du bekommst in Kürze eine Bestätigung per Email." @@ -2836,11 +2898,6 @@ msgstr "" msgid "List of all emails" msgstr "Liste alle E-Mails" -#: core/templates/core/email_list.html:39 shifts/models.py:502 -#: shifts/models.py:1071 shifts/templates/shifts/user_shift_account_log.html:29 -msgid "Description" -msgstr "Beschreibung" - #: core/templates/core/email_list.html:40 msgid "Subject" msgstr "Betreff" @@ -3039,10 +3096,6 @@ msgstr "Notiz hinzufügen" msgid "Log Type" msgstr "" -#: shifts/apps.py:36 shifts/templates/shifts/user_shifts_overview_tag.html:8 -msgid "Shifts" -msgstr "Schichten" - #: shifts/apps.py:39 shifts/templates/shifts/shift_calendar_future.html:4 #: shifts/templates/shifts/shift_calendar_future.html:7 msgid "Shift calendar" From 54f267aba3266bc7e4f9d4ecf4fff3fc2b770411 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:08:06 +0200 Subject: [PATCH 08/23] remove language, add status --- tapir/coop/templates/coop/user_profile_pdf.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index b2324323e..d93d3f326 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -3,6 +3,7 @@ {% load django_bootstrap5 %} {% load i18n %} {% load utils %} +{% load coop %} @@ -89,9 +90,9 @@

{% translate "Personal Data" %}

{{ person.get_display_address|default:"-" }}
-
{% translate "Language" %}
+
{% translate "Status" %}
- {{ person.get_preferred_language_display }} + {% member_status_colored_text shareowner %}
From be2ba62866b968f6a709f6259e7dd2e94181cb3d Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:09:33 +0200 Subject: [PATCH 09/23] add shares --- .../coop/templates/coop/user_profile_pdf.html | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index d93d3f326..956e8a09c 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -96,6 +96,45 @@

{% translate "Personal Data" %}

+
+

{% translate "Shares" %}

+ {% if shareowner.share_ownerships.all %} + + + + + + + + + + + {% for ownership in shareowner.share_ownerships.all %} + + + + + + + {% endfor %} + +
#{% translate "Starts at" %}{% translate "Ends at" %}{% translate "Status" %}
{{ ownership.id }}{{ ownership.start_date|date:"d.m.Y"|default:"-" }} + {% if ownership.end_date %} + {{ ownership.end_date|date:"d.m.Y" }} + {% else %} + - + {% endif %} + + {% if ownership.is_active %} + {% translate "Active" %} + {% else %} + {% translate "Sold or future" %} + {% endif %} +
+ {% else %} +
{% translate "No shares found." %}
+ {% endif %} +

{% translate "Shifts" %}

{% if attendances %} From 370ebff5b3b6455c08920df3c529baa3c1b27c3e Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:10:54 +0200 Subject: [PATCH 10/23] consistent date --- tapir/coop/templates/coop/user_profile_pdf.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 956e8a09c..db865033a 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -84,7 +84,7 @@

{% translate "Personal Data" %}

{% translate "Date of Birth" %}
- {{ person.birthdate|date:"j. F Y"|default:"-" }} + {{ person.birthdate|date:"d.m.Y"|default:"-" }}
{% translate "Address" %}
From 4c4c101b4708c1813ea6f95b98143351220b0d81 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:12:30 +0200 Subject: [PATCH 11/23] =?UTF-8?q?Tabellen=C3=BCberschriften=20responsiver?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tapir/coop/templates/coop/user_profile_pdf.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index db865033a..61bf7fe10 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -102,10 +102,10 @@

{% translate "Shares" %}

- - - - + + + + From fdd6c6c3e0a1b7389d75d30978361042d3f357b3 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:14:40 +0200 Subject: [PATCH 12/23] css --- .../coop/templates/coop/user_profile_pdf.html | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 61bf7fe10..083ce67af 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -55,6 +55,38 @@ border-bottom: 1px solid #ddd; padding-bottom: 5px; } + body { + font-family: Arial, sans-serif; + color: #333; + line-height: 1.4; + } + + h1 { + font-size: 14pt; + margin-bottom: 20px; + padding-bottom: 10px; + border-bottom: 2px solid #333; + } + + table { + page-break-inside: avoid; + } + + .section { + page-break-inside: avoid; + } + + th { + background-color: #f5f5f5; + } + + .footer { + margin-top: 40px; + padding-top: 10px; + border-top: 1px solid #ddd; + font-size: 8pt; + color: #999; + } @@ -98,7 +130,7 @@

{% translate "Personal Data" %}

{% translate "Shares" %}

- {% if shareowner.share_ownerships.all %} + {% if shareowner.share_ownerships.all|length > 0 %}
#{% translate "Starts at" %}{% translate "Ends at" %}{% translate "Status" %}#{% translate "Starts at" %}{% translate "Ends at" %}{% translate "Status" %}
From 7ad5dbb91f1d148296cb641c9b85cc4c5deec7ff Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:26:49 +0200 Subject: [PATCH 13/23] {% get_current_language as LANGUAGE_CODE %} --- tapir/coop/templates/coop/user_profile_pdf.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 083ce67af..442cc0d7c 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -4,7 +4,8 @@ {% load i18n %} {% load utils %} {% load coop %} - +{% get_current_language as LANGUAGE_CODE %} + From 11ca9aa22cb0a579c876234c1d2528abe7e2dd36 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:33:36 +0200 Subject: [PATCH 14/23] PDF/A-1b --- tapir/coop/templates/coop/user_profile_pdf.html | 4 +--- tapir/coop/views/shareowner.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 442cc0d7c..a8b7590d5 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -57,9 +57,7 @@ padding-bottom: 5px; } body { - font-family: Arial, sans-serif; - color: #333; - line-height: 1.4; + font-family: 'DejaVu Sans', 'Liberation Sans', Arial, sans-serif; } h1 { diff --git a/tapir/coop/views/shareowner.py b/tapir/coop/views/shareowner.py index 8530e8962..b57927f20 100644 --- a/tapir/coop/views/shareowner.py +++ b/tapir/coop/views/shareowner.py @@ -1142,7 +1142,7 @@ def render_to_response(self, context, **response_kwargs): html = weasyprint.HTML( string=html_string, base_url=request.build_absolute_uri("/") ) - pdf = html.write_pdf() + pdf = html.write_pdf(pdf_variant="pdf/a-1b") response = HttpResponse(pdf, content_type="application/pdf") filename = f"user-{self.object.pk}-profile.pdf" From 808a30d062cb066dc3ac9a54a573032696878777 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:40:50 +0200 Subject: [PATCH 15/23] replace person by shareowner --- tapir/coop/templates/coop/user_profile_pdf.html | 14 +++++++------- tapir/coop/views/shareowner.py | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index a8b7590d5..8968aae8e 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -95,31 +95,31 @@

{% translate "Personal Data" %}

{% translate "Name" %}
- {{ person.first_name }} {{ person.last_name }} + {{ shareowner.get_info.first_name }} {{ shareowner.get_info.last_name }}
{% translate "Email" %}
- {% if person.email %} - {{ person.email }} + {% if shareowner.get_info.email %} + {{ shareowner.get_info.email }} {% else %} - {% endif %}
{% translate "Phone" %}
- {% if person.phone_number %} - {{ person.phone_number }} + {% if shareowner.get_info.phone_number %} + {{ shareowner.get_info.phone_number }} {% else %} - {% endif %}
{% translate "Date of Birth" %}
- {{ person.birthdate|date:"d.m.Y"|default:"-" }} + {{ shareowner.get_info.birthdate|date:"d.m.Y"|default:"-" }}
{% translate "Address" %}
- {{ person.get_display_address|default:"-" }} + {{ shareowner.get_info.get_display_address|default:"-" }}
{% translate "Status" %}
diff --git a/tapir/coop/views/shareowner.py b/tapir/coop/views/shareowner.py index b57927f20..a9a6c22b1 100644 --- a/tapir/coop/views/shareowner.py +++ b/tapir/coop/views/shareowner.py @@ -1116,7 +1116,6 @@ class UserProfilePDFView(generic.DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) shareowner = self.object - person = getattr(shareowner, "user", None) or shareowner attendances = [] if shareowner.pk and shareowner.user is not None: @@ -1126,7 +1125,6 @@ def get_context_data(self, **kwargs): context.update( { - "person": person, "attendances": attendances, "shareowner": shareowner, "generated_at": timezone.now(), From 70e83ff9c0cfee08f6e488fe79082f7f340392e5 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:43:25 +0200 Subject: [PATCH 16/23] translation --- .../coop/templates/coop/user_profile_pdf.html | 4 +- .../locale/de/LC_MESSAGES/django.po | 68 ++++++++++--------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 8968aae8e..4e9ab1c2d 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -105,7 +105,7 @@

{% translate "Personal Data" %}

- {% endif %}
-
{% translate "Phone" %}
+
{% translate "Phone number" %}
{% if shareowner.get_info.phone_number %} {{ shareowner.get_info.phone_number }} @@ -113,7 +113,7 @@

{% translate "Personal Data" %}

- {% endif %}
-
{% translate "Date of Birth" %}
+
{% translate "Birthdate" %}
{{ shareowner.get_info.birthdate|date:"d.m.Y"|default:"-" }}
diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po index d56126666..4f242484b 100644 --- a/tapir/translations/locale/de/LC_MESSAGES/django.po +++ b/tapir/translations/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-12 09:54+0200\n" +"POT-Creation-Date: 2026-07-12 10:41+0200\n" "PO-Revision-Date: 2025-07-07 13:06+0000\n" "Last-Translator: Weblate Admin \n" "Language-Team: German \n" @@ -73,6 +73,7 @@ msgstr "Pronomen" #: coop/templates/coop/draftuser_detail.html:71 #: coop/templates/coop/draftuser_detail.html:142 #: coop/templates/coop/shareowner_detail.html:51 +#: coop/templates/coop/user_profile_pdf.html:108 msgid "Phone number" msgstr "Telefonnummer" @@ -80,6 +81,7 @@ msgstr "Telefonnummer" #: coop/models.py:73 coop/models.py:448 #: coop/templates/coop/draftuser_detail.html:146 #: coop/templates/coop/shareowner_detail.html:55 +#: coop/templates/coop/user_profile_pdf.html:116 msgid "Birthdate" msgstr "Geburtsdatum" @@ -316,7 +318,7 @@ msgstr "Mitglied" #: accounts/templates/accounts/user_detail.html:27 #: coop/templates/coop/shareowner_detail.html:17 -#: coop/templates/coop/user_profile_pdf.html:62 +#: coop/templates/coop/user_profile_pdf.html:94 msgid "Personal Data" msgstr "Persönliche Daten" @@ -357,7 +359,7 @@ msgstr "Name und Pronomen bearbeiten" #: coop/templates/coop/draftuser_detail.html:70 #: coop/templates/coop/draftuser_detail.html:130 #: coop/templates/coop/shareowner_detail.html:43 -#: coop/templates/coop/user_profile_pdf.html:64 coop/views/draftuser.py:260 +#: coop/templates/coop/user_profile_pdf.html:96 coop/views/draftuser.py:260 #: core/templates/core/email_list.html:38 #: core/templates/core/featureflag_list.html:18 #: financingcampaign/templates/financingcampaign/general.html:25 @@ -374,7 +376,7 @@ msgstr "Nutzer*innenname" #: coop/templates/coop/draftuser_detail.html:73 #: coop/templates/coop/draftuser_detail.html:138 #: coop/templates/coop/shareowner_detail.html:47 -#: coop/templates/coop/user_profile_pdf.html:68 +#: coop/templates/coop/user_profile_pdf.html:100 msgid "Email" msgstr "E-Mail-Adresse" @@ -394,7 +396,7 @@ msgstr "Fehlend" #: coop/templates/coop/draftuser_detail.html:72 #: coop/templates/coop/draftuser_detail.html:156 #: coop/templates/coop/shareowner_detail.html:65 -#: coop/templates/coop/user_profile_pdf.html:88 +#: coop/templates/coop/user_profile_pdf.html:120 msgid "Address" msgstr "Adresse" @@ -818,7 +820,7 @@ msgstr "Investierend" #: coop/models.py:369 coop/templates/coop/draftuser_detail.html:171 #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:115 -#: coop/views/statistics.py:135 +#: coop/templates/coop/user_profile_pdf.html:156 coop/views/statistics.py:135 msgid "Active" msgstr "Aktiv" @@ -1026,7 +1028,9 @@ msgstr "Liste ähnlicher Mitglieder" #: coop/templates/coop/draftuser_detail.html:69 #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:35 #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:102 -#: coop/templates/coop/user_profile_pdf.html:106 coop/views/shareowner.py:612 +#: coop/templates/coop/user_profile_pdf.html:124 +#: coop/templates/coop/user_profile_pdf.html:139 +#: coop/templates/coop/user_profile_pdf.html:177 coop/views/shareowner.py:612 #: shifts/templates/shifts/user_shifts_overview_tag.html:26 msgid "Status" msgstr "Status" @@ -2555,14 +2559,17 @@ msgid "List of shares owned by this member" msgstr "Liste der Anteile die dieses Mitglied gehören" #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:100 +#: coop/templates/coop/user_profile_pdf.html:137 msgid "Starts at" msgstr "Anfangsdatum" #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:101 +#: coop/templates/coop/user_profile_pdf.html:138 msgid "Ends at" msgstr "Endet am" #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:117 +#: coop/templates/coop/user_profile_pdf.html:158 msgid "Sold or future" msgstr "" @@ -2596,59 +2603,49 @@ msgstr "Mitgliedsbestätigung per Mail senden" msgid "User is not a cooperative member." msgstr "Benutzer*in ist kein Genossenschaftsmitglied." -#: coop/templates/coop/user_profile_pdf.html:10 -#: coop/templates/coop/user_profile_pdf.html:60 +#: coop/templates/coop/user_profile_pdf.html:12 +#: coop/templates/coop/user_profile_pdf.html:92 msgid "Member Profile" msgstr "Mitgliederprofil" -#: coop/templates/coop/user_profile_pdf.html:76 -msgid "Phone" -msgstr "" - -#: coop/templates/coop/user_profile_pdf.html:84 -msgid "Date of Birth" -msgstr "" +#: coop/templates/coop/user_profile_pdf.html:131 +msgid "Shares" +msgstr "Anteile" -#: coop/templates/coop/user_profile_pdf.html:92 -#, fuzzy -#| msgid "Preferred Language" -msgid "Language" -msgstr "Bevorzugte Sprache" +#: coop/templates/coop/user_profile_pdf.html:166 +msgid "No shares found." +msgstr "Keine Anteile gefunden" -#: coop/templates/coop/user_profile_pdf.html:99 shifts/apps.py:36 +#: coop/templates/coop/user_profile_pdf.html:170 shifts/apps.py:36 #: shifts/templates/shifts/user_shifts_overview_tag.html:8 msgid "Shifts" msgstr "Schichten" -#: coop/templates/coop/user_profile_pdf.html:104 +#: coop/templates/coop/user_profile_pdf.html:175 msgid "Date & Time" msgstr "" -#: coop/templates/coop/user_profile_pdf.html:105 +#: coop/templates/coop/user_profile_pdf.html:176 #: core/templates/core/email_list.html:39 shifts/models.py:502 #: shifts/models.py:1071 shifts/templates/shifts/user_shift_account_log.html:29 msgid "Description" msgstr "Beschreibung" -#: coop/templates/coop/user_profile_pdf.html:123 +#: coop/templates/coop/user_profile_pdf.html:194 msgid "(Slot removed)" msgstr "" -#: coop/templates/coop/user_profile_pdf.html:132 +#: coop/templates/coop/user_profile_pdf.html:203 #, fuzzy #| msgid "" #| "\n" #| " You completed your shift\n" msgid "No completed shifts found." -msgstr "" -"\n" -"Du hast deine Schicht beendet.\n" +msgstr "Keine Schichten gefunden" -#: coop/templates/coop/user_profile_pdf.html:135 -#, fuzzy -#| msgid "Generated from" +#: coop/templates/coop/user_profile_pdf.html:206 msgid "Generated on" -msgstr "Erzeugt von" +msgstr "Erzeugt am" #: coop/views/draftuser.py:89 coop/views/draftuser.py:94 #, python-format @@ -6625,6 +6622,11 @@ msgstr "%(name)s ist kein Mitglied der Genossenschaft. Vielleicht haben sie dere msgid "%(name)s has not attended a welcome session yet. Make sure they plan to do it!" msgstr "%(name)s hat an dem Willkommenstreffen noch nicht teilgenommen. Stelle sicher, dass er*sie es entsprechend einplant!" +#, fuzzy +#~| msgid "Preferred Language" +#~ msgid "Language" +#~ msgstr "Bevorzugte Sprache" + #, fuzzy, python-format #~| msgid "" #~| "\n" From 7bd93726038c232c75f53d41b905ae362d94a02d Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:52:02 +0200 Subject: [PATCH 17/23] SHIFT_RETENTION_YEARS --- tapir/coop/templates/coop/user_profile_pdf.html | 2 +- tapir/coop/views/shareowner.py | 14 +++++++++++--- tapir/settings.py | 3 +++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index 4e9ab1c2d..cd8fb3103 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -167,7 +167,7 @@

{% translate "Shares" %}

{% endif %}
-

{% translate "Shifts" %}

+

{% translate "Shifts" %} ({% blocktranslate count years=SHIFT_RETENTION_YEARS %}last year{% plural %}max. last {{ years }} years{% endblocktranslate %})

{% if attendances %}
diff --git a/tapir/coop/views/shareowner.py b/tapir/coop/views/shareowner.py index a9a6c22b1..c061c1b76 100644 --- a/tapir/coop/views/shareowner.py +++ b/tapir/coop/views/shareowner.py @@ -5,6 +5,7 @@ import django_filters import django_tables2 import weasyprint +from dateutil.relativedelta import relativedelta from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required @@ -1119,13 +1120,20 @@ def get_context_data(self, **kwargs): attendances = [] if shareowner.pk and shareowner.user is not None: - attendances = shareowner.user.shift_attendances.select_related( - "slot", "slot__shift" - ).order_by("slot__shift__start_time") + cutoff_date = timezone.now() - relativedelta( + years=settings.SHIFT_RETENTION_YEARS + ) + + attendances = ( + shareowner.user.shift_attendances.select_related("slot", "slot__shift") + .filter(slot__shift__start_time__gte=cutoff_date) + .order_by("slot__shift__start_time") + ) context.update( { "attendances": attendances, + "SHIFT_RETENTION_YEARS": settings.SHIFT_RETENTION_YEARS, "shareowner": shareowner, "generated_at": timezone.now(), } diff --git a/tapir/settings.py b/tapir/settings.py index f64afa8a1..e1600c046 100644 --- a/tapir/settings.py +++ b/tapir/settings.py @@ -438,3 +438,6 @@ ) SESSION_COOKIE_AGE = 86400 # one day + +# Duration of years, after which shifts are not relevant enough to be saved +SHIFT_RETENTION_YEARS = 8 From 68d65abc40fe169b761c27365e73008c9f4dc4cf Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:52:42 +0200 Subject: [PATCH 18/23] trans --- .../locale/de/LC_MESSAGES/django.po | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po index 4f242484b..880ff3073 100644 --- a/tapir/translations/locale/de/LC_MESSAGES/django.po +++ b/tapir/translations/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-12 10:41+0200\n" +"POT-Creation-Date: 2026-07-12 10:52+0200\n" "PO-Revision-Date: 2025-07-07 13:06+0000\n" "Last-Translator: Weblate Admin \n" "Language-Team: German \n" @@ -536,8 +536,8 @@ msgstr "Schickt mir eine Anleitung!" msgid "Enter a valid username. This value may contain only letters, numbers, and ./-/_ characters." msgstr "Der angegebene Name ist ungültig. Er darf nur Buchstaben, Zahlen und die Symbole ./-/_ enthalten." -#: accounts/views.py:129 accounts/views.py:134 coop/views/shareowner.py:286 -#: coop/views/shareowner.py:291 +#: accounts/views.py:129 accounts/views.py:134 coop/views/shareowner.py:287 +#: coop/views/shareowner.py:292 #, python-format msgid "Edit member: %(name)s" msgstr "Mitglied bearbeiten: %(name)s" @@ -1030,7 +1030,7 @@ msgstr "Liste ähnlicher Mitglieder" #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:102 #: coop/templates/coop/user_profile_pdf.html:124 #: coop/templates/coop/user_profile_pdf.html:139 -#: coop/templates/coop/user_profile_pdf.html:177 coop/views/shareowner.py:612 +#: coop/templates/coop/user_profile_pdf.html:177 coop/views/shareowner.py:613 #: shifts/templates/shifts/user_shifts_overview_tag.html:26 msgid "Status" msgstr "Status" @@ -2621,6 +2621,13 @@ msgstr "Keine Anteile gefunden" msgid "Shifts" msgstr "Schichten" +#: coop/templates/coop/user_profile_pdf.html:170 +#, python-format +msgid "last year" +msgid_plural "max. last %(years)s years" +msgstr[0] "" +msgstr[1] "" + #: coop/templates/coop/user_profile_pdf.html:175 msgid "Date & Time" msgstr "" @@ -2723,71 +2730,71 @@ msgstr "Auszahlungsende" msgid "Cancel membership of %(name)s" msgstr "Beende Mitgliedschaft von %(name)s" -#: coop/views/shareowner.py:147 coop/views/shareowner.py:152 +#: coop/views/shareowner.py:148 coop/views/shareowner.py:153 #, python-format msgid "Edit share: %(name)s" msgstr "Anteil bearbeiten: %(name)s" -#: coop/views/shareowner.py:172 coop/views/shareowner.py:177 +#: coop/views/shareowner.py:173 coop/views/shareowner.py:178 #, python-format msgid "Add shares to %(name)s" msgstr "Anteile zu %(name)s hinzufügen" -#: coop/views/shareowner.py:391 +#: coop/views/shareowner.py:392 msgid "Membership confirmation email sent." msgstr "Mitgliedsbestätigung per Mail gesendet." -#: coop/views/shareowner.py:613 shifts/templates/shifts/shift_filters.html:45 +#: coop/views/shareowner.py:614 shifts/templates/shifts/shift_filters.html:45 msgid "Any" msgstr "Alle" -#: coop/views/shareowner.py:618 +#: coop/views/shareowner.py:619 #: shifts/templates/shifts/user_shifts_overview_tag.html:79 msgid "Shift Status" msgstr "Schichtstatus" -#: coop/views/shareowner.py:626 +#: coop/views/shareowner.py:627 msgid "Is registered to an ABCD-slot that requires a qualification" msgstr "Ist für eine ABCD-Schicht eingetragen, die Qualifikation erfordert" -#: coop/views/shareowner.py:634 +#: coop/views/shareowner.py:635 msgid "Is registered to a slot that requires a qualification" msgstr "Ist für eine Schicht eingetragen, die Qualifikation erfordert" -#: coop/views/shareowner.py:642 +#: coop/views/shareowner.py:643 msgid "Has qualification" msgstr "Hat Qualifikation" -#: coop/views/shareowner.py:650 +#: coop/views/shareowner.py:651 msgid "Does not have qualification" msgstr "Hat die Qualifikation nicht" -#: coop/views/shareowner.py:657 shifts/forms.py:788 +#: coop/views/shareowner.py:658 shifts/forms.py:788 msgid "ABCD Week" msgstr "ABCD-Woche" -#: coop/views/shareowner.py:660 +#: coop/views/shareowner.py:661 msgid "Is fully paid" msgstr "Hat vollständig bezahlt" -#: coop/views/shareowner.py:663 +#: coop/views/shareowner.py:664 msgid "Name or member ID" msgstr "Name oder Mitgliedsnummer" -#: coop/views/shareowner.py:667 +#: coop/views/shareowner.py:668 msgid "Is currently exempted from shifts" msgstr "Ist derzeit von der Schichtarbeit befreit" -#: coop/views/shareowner.py:672 +#: coop/views/shareowner.py:673 msgid "Shift Name" msgstr "Schichtname" -#: coop/views/shareowner.py:988 +#: coop/views/shareowner.py:989 msgctxt "Willing to give a share" msgid "No" msgstr "Nein" -#: coop/views/shareowner.py:1093 +#: coop/views/shareowner.py:1094 msgid "Thank you for signing additional shares, we truly appreciate your contribution and commitment! You will receive an email confirmation soon." msgstr "Vielen Dank für das Zeichnen weiterer Anteile, wir freuen und bedanken uns! Du bekommst in Kürze eine Bestätigung per Email." From bc8fbbf1ffc3f5abf44decab409f02c5be1da7eb Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Sun, 12 Jul 2026 11:02:13 +0200 Subject: [PATCH 19/23] payments --- .../coop/templates/coop/user_profile_pdf.html | 27 +++++++++ .../locale/de/LC_MESSAGES/django.po | 59 +++++++++++-------- 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index cd8fb3103..a68b31253 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -166,6 +166,33 @@

{% translate "Shares" %}

{% translate "No shares found." %}
{% endif %} +
+

{% translate "Payments" %}

+ {% if shareowner.credited_payments.all|length > 0 %} +
+ + + + + + + + + + {% for payment in shareowner.credited_payments.all %} + + + + + + + {% endfor %} + +
{% translate "ID" %}{% translate "Date" %}{% translate "Description" %}{% translate "Amount" %}
{{ payment.id }}{{ payment.payment_date|date:"d.m.Y"|default:"-" }}{{ payment.description|default:"-" }}{{ payment.amount|floatformat:2 }} €
+ {% else %} +
{% translate "No payments found." %}
+ {% endif %} +

{% translate "Shifts" %} ({% blocktranslate count years=SHIFT_RETENTION_YEARS %}last year{% plural %}max. last {{ years }} years{% endblocktranslate %})

{% if attendances %} diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po index 880ff3073..6bb8f7628 100644 --- a/tapir/translations/locale/de/LC_MESSAGES/django.po +++ b/tapir/translations/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-12 10:52+0200\n" +"POT-Creation-Date: 2026-07-12 11:01+0200\n" "PO-Revision-Date: 2025-07-07 13:06+0000\n" "Last-Translator: Weblate Admin \n" "Language-Team: German \n" @@ -872,7 +872,7 @@ msgstr "Zahlendes Mitglied" msgid "Credited member" msgstr "Empfangendes Mitglied" -#: coop/models.py:585 +#: coop/models.py:585 coop/templates/coop/user_profile_pdf.html:178 msgid "Amount" msgstr "Betrag" @@ -1030,7 +1030,7 @@ msgstr "Liste ähnlicher Mitglieder" #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:102 #: coop/templates/coop/user_profile_pdf.html:124 #: coop/templates/coop/user_profile_pdf.html:139 -#: coop/templates/coop/user_profile_pdf.html:177 coop/views/shareowner.py:613 +#: coop/templates/coop/user_profile_pdf.html:204 coop/views/shareowner.py:613 #: shifts/templates/shifts/user_shifts_overview_tag.html:26 msgid "Status" msgstr "Status" @@ -2110,6 +2110,7 @@ msgstr "Allgemeine Tapir-Konten" #: coop/templates/coop/incoming_payment_list.html:10 #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:172 +#: coop/templates/coop/user_profile_pdf.html:170 msgid "Payments" msgstr "Zahlungen" @@ -2616,33 +2617,53 @@ msgstr "Anteile" msgid "No shares found." msgstr "Keine Anteile gefunden" -#: coop/templates/coop/user_profile_pdf.html:170 shifts/apps.py:36 +#: coop/templates/coop/user_profile_pdf.html:175 +msgid "ID" +msgstr "" + +#: coop/templates/coop/user_profile_pdf.html:176 +#: financingcampaign/templates/financingcampaign/general.html:111 +#: log/templates/log/log_entry_list_tag.html:23 +#: shifts/templates/shifts/user_shift_account_log.html:26 +#: statistics/templates/statistics/tags/credit_account_card.html:17 +#: statistics/templates/statistics/tags/purchase_statistics_card.html:18 +msgid "Date" +msgstr "Datum" + +#: coop/templates/coop/user_profile_pdf.html:177 +#: coop/templates/coop/user_profile_pdf.html:203 +#: core/templates/core/email_list.html:39 shifts/models.py:502 +#: shifts/models.py:1071 shifts/templates/shifts/user_shift_account_log.html:29 +msgid "Description" +msgstr "Beschreibung" + +#: coop/templates/coop/user_profile_pdf.html:193 +#, fuzzy +#| msgid "No shares found." +msgid "No payments found." +msgstr "Keine Anteile gefunden" + +#: coop/templates/coop/user_profile_pdf.html:197 shifts/apps.py:36 #: shifts/templates/shifts/user_shifts_overview_tag.html:8 msgid "Shifts" msgstr "Schichten" -#: coop/templates/coop/user_profile_pdf.html:170 +#: coop/templates/coop/user_profile_pdf.html:197 #, python-format msgid "last year" msgid_plural "max. last %(years)s years" msgstr[0] "" msgstr[1] "" -#: coop/templates/coop/user_profile_pdf.html:175 +#: coop/templates/coop/user_profile_pdf.html:202 msgid "Date & Time" msgstr "" -#: coop/templates/coop/user_profile_pdf.html:176 -#: core/templates/core/email_list.html:39 shifts/models.py:502 -#: shifts/models.py:1071 shifts/templates/shifts/user_shift_account_log.html:29 -msgid "Description" -msgstr "Beschreibung" - -#: coop/templates/coop/user_profile_pdf.html:194 +#: coop/templates/coop/user_profile_pdf.html:221 msgid "(Slot removed)" msgstr "" -#: coop/templates/coop/user_profile_pdf.html:203 +#: coop/templates/coop/user_profile_pdf.html:230 #, fuzzy #| msgid "" #| "\n" @@ -2650,7 +2671,7 @@ msgstr "" msgid "No completed shifts found." msgstr "Keine Schichten gefunden" -#: coop/templates/coop/user_profile_pdf.html:206 +#: coop/templates/coop/user_profile_pdf.html:233 msgid "Generated on" msgstr "Erzeugt am" @@ -3006,14 +3027,6 @@ msgstr "" msgid "The list of all datapoints" msgstr "" -#: financingcampaign/templates/financingcampaign/general.html:111 -#: log/templates/log/log_entry_list_tag.html:23 -#: shifts/templates/shifts/user_shift_account_log.html:26 -#: statistics/templates/statistics/tags/credit_account_card.html:17 -#: statistics/templates/statistics/tags/purchase_statistics_card.html:18 -msgid "Date" -msgstr "Datum" - #: financingcampaign/templates/financingcampaign/general.html:112 #: shifts/templates/shifts/user_shift_account_log.html:27 msgid "Value" From 1c537656d6b1c7d84d9efb89212a863fc76d1251 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Wed, 15 Jul 2026 18:49:42 +0200 Subject: [PATCH 20/23] shift-account-entries --- .../coop/templates/coop/user_profile_pdf.html | 27 +++++++++++++++++++ tapir/coop/views/shareowner.py | 13 +++++++++ 2 files changed, 40 insertions(+) diff --git a/tapir/coop/templates/coop/user_profile_pdf.html b/tapir/coop/templates/coop/user_profile_pdf.html index a68b31253..af20ee20f 100644 --- a/tapir/coop/templates/coop/user_profile_pdf.html +++ b/tapir/coop/templates/coop/user_profile_pdf.html @@ -230,6 +230,33 @@

{% translate "Shifts" %} ({% blocktranslate count years=SHIFT_RETENTION_YEAR
{% translate "No completed shifts found." %}
{% endif %}

+
+

{% translate "Shift account history" %} ({% blocktranslate count years=SHIFT_RETENTION_YEARS %}last year{% plural %}max. last {{ years }} years{% endblocktranslate %})

+ {% if attendances %} + + + + + + + + + + + {% for entry_data in entries_data %} + + + + + + + {% endfor %} + +
{% translate 'Date' %}{% translate 'Value' %}{% translate 'Balance at date' %}{% translate 'Description' %}
{{ entry_data.entry.date|date:"d.m.Y H:i" }}{{ entry_data.entry.value }}{{ entry_data.balance_at_date }}{{ entry_data.entry.description }}
+ {% else %} +
{% translate "No completed shifts found." %}
+ {% endif %} +
diff --git a/tapir/coop/views/shareowner.py b/tapir/coop/views/shareowner.py index c061c1b76..bcb58e42c 100644 --- a/tapir/coop/views/shareowner.py +++ b/tapir/coop/views/shareowner.py @@ -95,6 +95,7 @@ SHIFT_ATTENDANCE_MODE_CHOICES, SHIFT_USER_CAPABILITY_CHOICES, Shift, + ShiftAccountEntry, ShiftExemption, ShiftTemplateGroup, ) @@ -1129,6 +1130,17 @@ def get_context_data(self, **kwargs): .filter(slot__shift__start_time__gte=cutoff_date) .order_by("slot__shift__start_time") ) + entries_data = [ + { + "entry": entry, + "balance_at_date": shareowner.user.shift_user_data.get_account_balance( + at_date=entry.date + ), + } + for entry in ShiftAccountEntry.objects.filter( + user=shareowner.user, date__gte=cutoff_date + ).order_by("-date") + ] context.update( { @@ -1136,6 +1148,7 @@ def get_context_data(self, **kwargs): "SHIFT_RETENTION_YEARS": settings.SHIFT_RETENTION_YEARS, "shareowner": shareowner, "generated_at": timezone.now(), + "entries_data": entries_data, } ) return context From 8dd724ad9688cef306b1a9043fbe71ac3b9c8153 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Wed, 15 Jul 2026 18:58:50 +0200 Subject: [PATCH 21/23] translation --- .../locale/de/LC_MESSAGES/django.po | 72 +++++++++++-------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po index 6bb8f7628..b7981e185 100644 --- a/tapir/translations/locale/de/LC_MESSAGES/django.po +++ b/tapir/translations/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-12 11:01+0200\n" +"POT-Creation-Date: 2026-07-15 18:56+0200\n" "PO-Revision-Date: 2025-07-07 13:06+0000\n" "Last-Translator: Weblate Admin \n" "Language-Team: German \n" @@ -536,8 +536,8 @@ msgstr "Schickt mir eine Anleitung!" msgid "Enter a valid username. This value may contain only letters, numbers, and ./-/_ characters." msgstr "Der angegebene Name ist ungültig. Er darf nur Buchstaben, Zahlen und die Symbole ./-/_ enthalten." -#: accounts/views.py:129 accounts/views.py:134 coop/views/shareowner.py:287 -#: coop/views/shareowner.py:292 +#: accounts/views.py:129 accounts/views.py:134 coop/views/shareowner.py:288 +#: coop/views/shareowner.py:293 #, python-format msgid "Edit member: %(name)s" msgstr "Mitglied bearbeiten: %(name)s" @@ -1030,7 +1030,7 @@ msgstr "Liste ähnlicher Mitglieder" #: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:102 #: coop/templates/coop/user_profile_pdf.html:124 #: coop/templates/coop/user_profile_pdf.html:139 -#: coop/templates/coop/user_profile_pdf.html:204 coop/views/shareowner.py:613 +#: coop/templates/coop/user_profile_pdf.html:204 coop/views/shareowner.py:614 #: shifts/templates/shifts/user_shifts_overview_tag.html:26 msgid "Status" msgstr "Status" @@ -2622,6 +2622,7 @@ msgid "ID" msgstr "" #: coop/templates/coop/user_profile_pdf.html:176 +#: coop/templates/coop/user_profile_pdf.html:239 #: financingcampaign/templates/financingcampaign/general.html:111 #: log/templates/log/log_entry_list_tag.html:23 #: shifts/templates/shifts/user_shift_account_log.html:26 @@ -2632,6 +2633,7 @@ msgstr "Datum" #: coop/templates/coop/user_profile_pdf.html:177 #: coop/templates/coop/user_profile_pdf.html:203 +#: coop/templates/coop/user_profile_pdf.html:242 #: core/templates/core/email_list.html:39 shifts/models.py:502 #: shifts/models.py:1071 shifts/templates/shifts/user_shift_account_log.html:29 msgid "Description" @@ -2649,6 +2651,7 @@ msgid "Shifts" msgstr "Schichten" #: coop/templates/coop/user_profile_pdf.html:197 +#: coop/templates/coop/user_profile_pdf.html:234 #, python-format msgid "last year" msgid_plural "max. last %(years)s years" @@ -2664,6 +2667,7 @@ msgid "(Slot removed)" msgstr "" #: coop/templates/coop/user_profile_pdf.html:230 +#: coop/templates/coop/user_profile_pdf.html:257 #, fuzzy #| msgid "" #| "\n" @@ -2671,7 +2675,24 @@ msgstr "" msgid "No completed shifts found." msgstr "Keine Schichten gefunden" -#: coop/templates/coop/user_profile_pdf.html:233 +#: coop/templates/coop/user_profile_pdf.html:234 +#, fuzzy +#| msgid "Shift account log for: " +msgid "Shift account history" +msgstr "Schichtkonto-Protokoll für: " + +#: coop/templates/coop/user_profile_pdf.html:240 +#: financingcampaign/templates/financingcampaign/general.html:112 +#: shifts/templates/shifts/user_shift_account_log.html:27 +msgid "Value" +msgstr "Wert" + +#: coop/templates/coop/user_profile_pdf.html:241 +#: shifts/templates/shifts/user_shift_account_log.html:28 +msgid "Balance at date" +msgstr "" + +#: coop/templates/coop/user_profile_pdf.html:260 msgid "Generated on" msgstr "Erzeugt am" @@ -2751,71 +2772,71 @@ msgstr "Auszahlungsende" msgid "Cancel membership of %(name)s" msgstr "Beende Mitgliedschaft von %(name)s" -#: coop/views/shareowner.py:148 coop/views/shareowner.py:153 +#: coop/views/shareowner.py:149 coop/views/shareowner.py:154 #, python-format msgid "Edit share: %(name)s" msgstr "Anteil bearbeiten: %(name)s" -#: coop/views/shareowner.py:173 coop/views/shareowner.py:178 +#: coop/views/shareowner.py:174 coop/views/shareowner.py:179 #, python-format msgid "Add shares to %(name)s" msgstr "Anteile zu %(name)s hinzufügen" -#: coop/views/shareowner.py:392 +#: coop/views/shareowner.py:393 msgid "Membership confirmation email sent." msgstr "Mitgliedsbestätigung per Mail gesendet." -#: coop/views/shareowner.py:614 shifts/templates/shifts/shift_filters.html:45 +#: coop/views/shareowner.py:615 shifts/templates/shifts/shift_filters.html:45 msgid "Any" msgstr "Alle" -#: coop/views/shareowner.py:619 +#: coop/views/shareowner.py:620 #: shifts/templates/shifts/user_shifts_overview_tag.html:79 msgid "Shift Status" msgstr "Schichtstatus" -#: coop/views/shareowner.py:627 +#: coop/views/shareowner.py:628 msgid "Is registered to an ABCD-slot that requires a qualification" msgstr "Ist für eine ABCD-Schicht eingetragen, die Qualifikation erfordert" -#: coop/views/shareowner.py:635 +#: coop/views/shareowner.py:636 msgid "Is registered to a slot that requires a qualification" msgstr "Ist für eine Schicht eingetragen, die Qualifikation erfordert" -#: coop/views/shareowner.py:643 +#: coop/views/shareowner.py:644 msgid "Has qualification" msgstr "Hat Qualifikation" -#: coop/views/shareowner.py:651 +#: coop/views/shareowner.py:652 msgid "Does not have qualification" msgstr "Hat die Qualifikation nicht" -#: coop/views/shareowner.py:658 shifts/forms.py:788 +#: coop/views/shareowner.py:659 shifts/forms.py:788 msgid "ABCD Week" msgstr "ABCD-Woche" -#: coop/views/shareowner.py:661 +#: coop/views/shareowner.py:662 msgid "Is fully paid" msgstr "Hat vollständig bezahlt" -#: coop/views/shareowner.py:664 +#: coop/views/shareowner.py:665 msgid "Name or member ID" msgstr "Name oder Mitgliedsnummer" -#: coop/views/shareowner.py:668 +#: coop/views/shareowner.py:669 msgid "Is currently exempted from shifts" msgstr "Ist derzeit von der Schichtarbeit befreit" -#: coop/views/shareowner.py:673 +#: coop/views/shareowner.py:674 msgid "Shift Name" msgstr "Schichtname" -#: coop/views/shareowner.py:989 +#: coop/views/shareowner.py:990 msgctxt "Willing to give a share" msgid "No" msgstr "Nein" -#: coop/views/shareowner.py:1094 +#: coop/views/shareowner.py:1095 msgid "Thank you for signing additional shares, we truly appreciate your contribution and commitment! You will receive an email confirmation soon." msgstr "Vielen Dank für das Zeichnen weiterer Anteile, wir freuen und bedanken uns! Du bekommst in Kürze eine Bestätigung per Email." @@ -3027,11 +3048,6 @@ msgstr "" msgid "The list of all datapoints" msgstr "" -#: financingcampaign/templates/financingcampaign/general.html:112 -#: shifts/templates/shifts/user_shift_account_log.html:27 -msgid "Value" -msgstr "Wert" - #: financingcampaign/templates/financingcampaign/general.html:113 msgid "Linked source" msgstr "" @@ -4940,10 +4956,6 @@ msgstr "Füge per Hand einen Eintrag hinzu" msgid "List of changes to this members shift account " msgstr "" -#: shifts/templates/shifts/user_shift_account_log.html:28 -msgid "Balance at date" -msgstr "" - #: shifts/templates/shifts/user_shifts_overview_tag.html:20 msgid "Watched Shifts" msgstr "Beobachtete Schichten" From 650fdf94f7cae64de53a4393fcddcee6391d5cd5 Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Wed, 15 Jul 2026 19:01:59 +0200 Subject: [PATCH 22/23] permission --- tapir/coop/views/shareowner.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tapir/coop/views/shareowner.py b/tapir/coop/views/shareowner.py index bcb58e42c..078eaff29 100644 --- a/tapir/coop/views/shareowner.py +++ b/tapir/coop/views/shareowner.py @@ -1110,8 +1110,11 @@ def get_success_url(self): return self.get_share_owner().get_absolute_url() -class UserProfilePDFView(generic.DetailView): +class UserProfilePDFView( + LoginRequiredMixin, PermissionRequiredMixin, generic.DetailView +): model = ShareOwner + permission_required = PERMISSION_ACCOUNTS_MANAGE pk_url_kwarg = "pk" template_name = "coop/user_profile_pdf.html" From 8c6e334cf6600945f0cbc1cd2d89d1ae4a9e56ff Mon Sep 17 00:00:00 2001 From: crosspolar <18083323+crosspolar@users.noreply.github.com> Date: Mon, 27 Jul 2026 17:09:48 +0200 Subject: [PATCH 23/23] remove fuzzy translations --- tapir/translations/locale/de/LC_MESSAGES/django.po | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po index b7981e185..e47366732 100644 --- a/tapir/translations/locale/de/LC_MESSAGES/django.po +++ b/tapir/translations/locale/de/LC_MESSAGES/django.po @@ -2640,8 +2640,6 @@ msgid "Description" msgstr "Beschreibung" #: coop/templates/coop/user_profile_pdf.html:193 -#, fuzzy -#| msgid "No shares found." msgid "No payments found." msgstr "Keine Anteile gefunden" @@ -2668,16 +2666,10 @@ msgstr "" #: coop/templates/coop/user_profile_pdf.html:230 #: coop/templates/coop/user_profile_pdf.html:257 -#, fuzzy -#| msgid "" -#| "\n" -#| " You completed your shift\n" msgid "No completed shifts found." msgstr "Keine Schichten gefunden" #: coop/templates/coop/user_profile_pdf.html:234 -#, fuzzy -#| msgid "Shift account log for: " msgid "Shift account history" msgstr "Schichtkonto-Protokoll für: "