From 9a29ded81d709b865bd34c7358a8e0b26427ab65 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Fri, 17 Apr 2026 19:40:21 +0200
Subject: [PATCH 01/14] init
---
tapir/shifts/forms.py | 13 ++++++
.../migrations/0075_shifttemplate_end_date.py | 22 +++++++++
tapir/shifts/models.py | 14 ++++--
tapir/shifts/services/shift_generator.py | 9 +++-
.../shifts/shift_template_detail.html | 5 ++
.../shifts/shift_template_set_end_date.html | 29 ++++++++++++
tapir/shifts/urls.py | 6 +++
tapir/shifts/views/views.py | 46 +++++++++++++++++++
8 files changed, 138 insertions(+), 6 deletions(-)
create mode 100644 tapir/shifts/migrations/0075_shifttemplate_end_date.py
create mode 100644 tapir/shifts/templates/shifts/shift_template_set_end_date.html
diff --git a/tapir/shifts/forms.py b/tapir/shifts/forms.py
index 8fc2ee0bb..0f16ea153 100644
--- a/tapir/shifts/forms.py
+++ b/tapir/shifts/forms.py
@@ -459,6 +459,19 @@ def clean(self):
return result
+class ShiftTemplateEndDateForm(forms.ModelForm):
+ cancellation_reason = forms.CharField(label=_("Cancellation Reason"), required=True)
+
+ class Meta:
+ model = ShiftTemplate
+ fields = ["end_date"]
+ widgets = {"end_date": DateInputTapir()}
+
+ def __init__(self, shift_template=None, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.fields["end_date"].required = True
+
+
class CreateShiftAccountEntryForm(forms.ModelForm):
class Meta:
model = ShiftAccountEntry
diff --git a/tapir/shifts/migrations/0075_shifttemplate_end_date.py b/tapir/shifts/migrations/0075_shifttemplate_end_date.py
new file mode 100644
index 000000000..f0bee3db1
--- /dev/null
+++ b/tapir/shifts/migrations/0075_shifttemplate_end_date.py
@@ -0,0 +1,22 @@
+# Generated by Django 5.2.13 on 2026-04-17 16:42
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("shifts", "0074_alter_shift_num_required_attendances"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="shifttemplate",
+ name="end_date",
+ field=models.DateField(
+ blank=True,
+ help_text="All shifts after this date will be cancelled.",
+ null=True,
+ ),
+ ),
+ ]
diff --git a/tapir/shifts/models.py b/tapir/shifts/models.py
index b639b9778..315e9ebad 100644
--- a/tapir/shifts/models.py
+++ b/tapir/shifts/models.py
@@ -178,6 +178,11 @@ class ShiftTemplate(models.Model):
"This determines from which date shifts should be generated from this ABCD shift."
),
)
+ end_date = models.DateField(
+ blank=True,
+ null=True,
+ help_text=_("All shifts after this date will be cancelled."),
+ )
flexible_time = models.BooleanField(
verbose_name=_("Flexible time"),
help_text=_(
@@ -292,10 +297,11 @@ def update_future_generated_shifts_to_fit_this(self):
shift.update_to_fit_template()
def clean(self):
- if self.start_time >= self.end_time:
- raise ValidationError(
- f"The shift must end after it starts. Given start time: {self.start_time}. Given end time: {self.end_time}"
- )
+ if self.start_time and self.end_time:
+ if self.start_time >= self.end_time:
+ raise ValidationError(
+ f"The shift must end after it starts. Given start time: {self.start_time}. Given end time: {self.end_time}"
+ )
class RequiredCapabilitiesMixin:
diff --git a/tapir/shifts/services/shift_generator.py b/tapir/shifts/services/shift_generator.py
index ea4c828c6..c8b4e3902 100644
--- a/tapir/shifts/services/shift_generator.py
+++ b/tapir/shifts/services/shift_generator.py
@@ -56,8 +56,13 @@ def create_shifts_for_group(
start_date_in_the_past_or_null = Q(start_date__lte=at_date) | Q(
start_date__isnull=True
)
- shift_templates = ShiftTemplate.objects.filter(group=group).filter(
- start_date_in_the_past_or_null
+ end_date_in_the_future_or_null = Q(end_date__gte=at_date) | Q(
+ end_date__isnull=True
+ )
+ shift_templates = (
+ ShiftTemplate.objects.filter(group=group)
+ .filter(start_date_in_the_past_or_null)
+ .filter(end_date_in_the_future_or_null)
)
if filter_shift_template_ids is not None:
diff --git a/tapir/shifts/templates/shifts/shift_template_detail.html b/tapir/shifts/templates/shifts/shift_template_detail.html
index b1ee5d22d..132770826 100644
--- a/tapir/shifts/templates/shifts/shift_template_detail.html
+++ b/tapir/shifts/templates/shifts/shift_template_detail.html
@@ -28,6 +28,11 @@
diff --git a/tapir/shifts/templates/shifts/shift_template_set_end_date.html b/tapir/shifts/templates/shifts/shift_template_set_end_date.html
new file mode 100644
index 000000000..938bb683b
--- /dev/null
+++ b/tapir/shifts/templates/shifts/shift_template_set_end_date.html
@@ -0,0 +1,29 @@
+{% extends "shifts/base.html" %}
+{% load django_bootstrap5 %}
+{% load static %}
+{% load i18n %}
+{% load core %}
+{% block title %}
+ {% translate 'Set end date for' %}: {{ shift_template.get_display_name }}
+{% endblock title %}
+{% block content %}
+
+{% endblock content %}
diff --git a/tapir/shifts/urls.py b/tapir/shifts/urls.py
index 7ec077acd..9f6281e50 100644
--- a/tapir/shifts/urls.py
+++ b/tapir/shifts/urls.py
@@ -1,6 +1,7 @@
from django.urls import path
from tapir.shifts import views
+from tapir.shifts.views import ShiftTemplateEndDateView
app_name = "shifts"
urlpatterns = [
@@ -240,4 +241,9 @@
views.RecurringShiftwatchListView.as_view(),
name="shiftwatch_overview",
),
+ path(
+ "shift_template//set_end_date/",
+ ShiftTemplateEndDateView.as_view(),
+ name="shift_template_set_end_date",
+ ),
]
diff --git a/tapir/shifts/views/views.py b/tapir/shifts/views/views.py
index 4897ebec6..8b61ffcc0 100644
--- a/tapir/shifts/views/views.py
+++ b/tapir/shifts/views/views.py
@@ -16,10 +16,12 @@
CreateView,
UpdateView,
RedirectView,
+ FormView,
)
from django.views.generic import DetailView, TemplateView
from django_tables2 import SingleTableView
from django_tables2.export import ExportMixin
+from redis.commands.search import result
from tapir.accounts.models import TapirUser
from tapir.core.config import (
@@ -40,6 +42,7 @@
CreateShiftAccountEntryForm,
ShiftWatchForm,
RecurringShiftWatchForm,
+ ShiftTemplateEndDateForm,
)
from tapir.shifts.models import (
@@ -56,6 +59,7 @@
ShiftUserData,
ShiftAccountEntry,
)
+from tapir.shifts.services.shift_cancellation_service import ShiftCancellationService
from tapir.shifts.services.shift_watch_creation_service import ShiftWatchCreator
from tapir.shifts.templatetags.shifts import shift_name_as_class
from tapir.utils.user_utils import UserUtils
@@ -289,6 +293,48 @@ def get_queryset(self):
)
+class ShiftTemplateEndDateView(
+ LoginRequiredMixin,
+ PermissionRequiredMixin,
+ # TapirFormMixin,
+ generic.UpdateView,
+):
+ permission_required = PERMISSION_SHIFTS_MANAGE
+ form_class = ShiftTemplateEndDateForm
+ template_name = "shifts/shift_template_set_end_date.html"
+ model = ShiftTemplate
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context["shift_template"] = self.object
+ return context
+
+ def get_success_url(self):
+ return reverse("shifts:shift_template_detail", kwargs={"pk": self.object.pk})
+
+ def form_valid(self, form):
+ with transaction.atomic():
+ response = super().form_valid(form)
+ end_date = form.cleaned_data["end_date"]
+ cancellation_reason = form.cleaned_data["cancellation_reason"]
+ shifts_to_cancel = Shift.objects.filter(
+ shift_template=self.object,
+ start_time__date__gt=end_date,
+ deleted=False,
+ cancelled=False,
+ )
+ for shift in shifts_to_cancel:
+ shift.cancelled_reason = cancellation_reason
+ ShiftCancellationService.cancel(shift)
+
+ messages.success(
+ self.request,
+ _("Shift template was successfully cancelled"),
+ )
+
+ return response
+
+
class ShiftUserDataTable(django_tables2.Table):
class Meta:
model = ShiftUserData
From 1d7136f3b50c6d44eb43207d1f951d498f4d9592 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Sat, 18 Apr 2026 07:39:34 +0200
Subject: [PATCH 02/14] translation
---
.../locale/de/LC_MESSAGES/django.po | 192 +++++++++++-------
1 file changed, 114 insertions(+), 78 deletions(-)
diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po
index cd6b9f553..e5998bd4e 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-03-15 12:03+0100\n"
+"POT-Creation-Date: 2026-04-18 07:38+0200\n"
"PO-Revision-Date: 2025-07-07 13:06+0000\n"
"Last-Translator: Weblate Admin \n"
"Language-Team: German \n"
@@ -343,7 +343,7 @@ msgstr "Benutzername bearbeiten"
#: core/templates/core/featureflag_list.html:30
#: shifts/templates/shifts/shift_detail.html:61
#: shifts/templates/shifts/shift_template_detail.html:29
-#: shifts/templates/shifts/shift_template_detail.html:117
+#: shifts/templates/shifts/shift_template_detail.html:122
#: shifts/templates/shifts/user_shifts_overview_tag.html:14
msgid "Edit"
msgstr "Bearbeiten"
@@ -1084,7 +1084,7 @@ msgstr "Bewerber*in erzeugen"
#: shifts/templates/shifts/register_user_to_shift_slot.html:27
#: shifts/templates/shifts/register_user_to_shift_slot_template.html:26
#: shifts/templates/shifts/shift_detail.html:243
-#: shifts/templates/shifts/shift_template_detail.html:88
+#: shifts/templates/shifts/shift_template_detail.html:93
msgid "Register"
msgstr "Anmelden"
@@ -2149,7 +2149,7 @@ msgstr ""
" "
#: coop/templates/coop/membershipresignation_detail.html:61
-#: shifts/models.py:536
+#: shifts/models.py:542
msgid "Cancellation reason"
msgstr "Grund der Kündigung"
@@ -2382,7 +2382,7 @@ msgid ""
msgstr ""
#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:56
-#: shifts/models.py:934 shifts/templates/shifts/shift_day_printable.html:214
+#: shifts/models.py:940 shifts/templates/shifts/shift_day_printable.html:214
#: shifts/templates/shifts/shift_day_printable.html:276
#: shifts/templates/shifts/shift_detail.html:298
#: shifts/templates/shifts/shift_detail_printable.html:51
@@ -2390,7 +2390,7 @@ msgid "Attended"
msgstr "Teilgenommen"
#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:58
-#: shifts/models.py:933
+#: shifts/models.py:939
msgid "Pending"
msgstr "Ausstehend"
@@ -2563,7 +2563,7 @@ msgstr "Hat Qualifikation"
msgid "Does not have qualification"
msgstr "Hat die Qualifikation nicht"
-#: coop/views/shareowner.py:647 shifts/forms.py:777
+#: coop/views/shareowner.py:647 shifts/forms.py:790
msgid "ABCD Week"
msgstr "ABCD-Woche"
@@ -2692,8 +2692,8 @@ msgstr ""
msgid "List of all emails"
msgstr "Liste alle E-Mails"
-#: core/templates/core/email_list.html:39 shifts/models.py:503
-#: shifts/models.py:1072 shifts/templates/shifts/user_shift_account_log.html:29
+#: core/templates/core/email_list.html:39 shifts/models.py:509
+#: shifts/models.py:1078 shifts/templates/shifts/user_shift_account_log.html:29
msgid "Description"
msgstr "Beschreibung"
@@ -3038,78 +3038,78 @@ msgstr "Das ausgewählte Mitglied muss ein investierendes Mitglied sein."
msgid "This member is registered to at least one ABCD shift. Please confirm the change of attendance mode with the checkbox below."
msgstr ""
-#: shifts/forms.py:497
+#: shifts/forms.py:463 shifts/forms.py:621
+msgid "Cancellation Reason"
+msgstr "Grund der Absage"
+
+#: shifts/forms.py:510
msgid "I have read the warning about the cancelled attendances and confirm that the exemption should be created"
msgstr "Ich habe die Warnung über die abgesagte Schicht-Anwesenheit gelesen und bestätige, dass die Befreiung erzeugt werden soll"
-#: shifts/forms.py:504
+#: shifts/forms.py:517
msgid "I have read the warning about the cancelled ABCD attendances and confirm that the exemption should be created"
msgstr "Ich habe die Warnung über die abgebrochene ABCD-Teilnahme gelesen und bestätige, dass die Befreiung erzeugt werden soll"
-#: shifts/forms.py:562
+#: shifts/forms.py:575
#, python-format
msgid "The user will be unregistered from the following ABCD shifts because the exemption is longer than %(number_of_cycles)s cycles: %(attendances_display)s "
msgstr "Das Mitglied wird von den folgenden ABCD-Schichten abgemeldet, weil die Befreiung länger als %(number_of_cycles)s Schichtzyklen ist: %(attendances_display)s "
-#: shifts/forms.py:583
+#: shifts/forms.py:596
msgid "This shift has been deleted. It is not possible to cancel it."
msgstr "Diese Schicht wurde bereits gelöscht. Es ist nicht möglich diese abzusagen."
-#: shifts/forms.py:594 shifts/templates/shifts/shift_detail.html:8
+#: shifts/forms.py:607 shifts/templates/shifts/shift_detail.html:8
#: shifts/templates/shifts/shift_detail.html:30
msgid "Shift"
msgstr "Schicht"
-#: shifts/forms.py:595
+#: shifts/forms.py:608
msgid "already cancelled"
msgstr "bereits bgesagt"
-#: shifts/forms.py:608
-msgid "Cancellation Reason"
-msgstr "Grund der Absage"
-
-#: shifts/forms.py:609
+#: shifts/forms.py:622
msgid "This reason will be applied to all cancelled shifts."
msgstr ""
-#: shifts/forms.py:637
+#: shifts/forms.py:650
msgid "I understand that updating this ABCD shift will update all the corresponding future shifts"
msgstr ""
-#: shifts/forms.py:656
+#: shifts/forms.py:669
msgid "ABCD-Week"
msgstr "ABCD-Woche"
-#: shifts/forms.py:660
+#: shifts/forms.py:673
msgid "Weekdays"
msgstr "Wochentage"
-#: shifts/forms.py:685
+#: shifts/forms.py:698
msgid "I understand that adding or editing a slot to this ABCD shift will affect all the corresponding future shifts"
msgstr ""
-#: shifts/forms.py:694
+#: shifts/forms.py:707
msgid "I understand that this will delete the shift exemption and create a membership pause"
msgstr ""
-#: shifts/forms.py:726 shifts/forms.py:782 shifts/views/views.py:379
-#: shifts/views/views.py:380
+#: shifts/forms.py:739 shifts/forms.py:795 shifts/views/views.py:425
+#: shifts/views/views.py:426
msgid "Shift changes you would like to be informed about"
msgstr "Schicht-Änderungen, bei denen du informiert werden möchtest"
-#: shifts/forms.py:771 shifts/templates/shifts/shift_template_detail.html:7
+#: shifts/forms.py:784 shifts/templates/shifts/shift_template_detail.html:7
#: shifts/templates/shifts/shift_template_detail.html:15
#: shifts/templates/shifts/user_shifts_overview_tag.html:31
#: shifts/templates/shifts/user_shifts_overview_tag.html:43
msgid "ABCD Shift"
msgstr "ABCD-Schicht"
-#: shifts/forms.py:788
+#: shifts/forms.py:801
#, python-format
msgid "If weekdays or %(shift_template_group)s are selected, %(shift_templates)s may not be selected, and vice versa."
msgstr ""
-#: shifts/forms.py:792
+#: shifts/forms.py:805
#, python-format
msgid "At least one of the fields (%(shift_templates)s, weekdays, or %(shift_template_group)s) must be selected."
msgstr ""
@@ -3174,7 +3174,7 @@ msgstr "Mir ist klar, dass ich bei dieser Schicht möglicherweise schwere Gewich
msgid "I understand that I may need to work high, for example up a ladder. I do not suffer from fear of heights."
msgstr "Mir ist klar, dass ich möglicherweise in großer Höhe arbeiten muss, zum Beispiel auf einer Leiter. Ich leide nicht unter Höhenangst."
-#: shifts/models.py:167 shifts/models.py:497
+#: shifts/models.py:167 shifts/models.py:503
msgid "If there are less members registered to a shift than that number, it will be highlighted in the shift calendar. The number of required attendances can't be higher than the slots in the resp. shift."
msgstr "Wenn weniger Mitlieder als diese Nummer zur Schicht registriert sind, wird diese blau angezeigt. Die Anzahl der benltigten Mitglieder kann nicht höher sein als die Anzahl vorhandener Slots."
@@ -3182,47 +3182,51 @@ msgstr "Wenn weniger Mitlieder als diese Nummer zur Schicht registriert sind, wi
msgid "This determines from which date shifts should be generated from this ABCD shift."
msgstr ""
-#: shifts/models.py:182 shifts/models.py:511
+#: shifts/models.py:184
+msgid "All shifts after this date will be cancelled."
+msgstr ""
+
+#: shifts/models.py:187 shifts/models.py:517
#: shifts/templates/shifts/shift_block_tag.html:11
msgid "Flexible time"
msgstr "Zeit flexibel"
-#: shifts/models.py:184 shifts/models.py:513
+#: shifts/models.py:189 shifts/models.py:519
msgid "If enabled, members who register for that shift can choose themselves the time where they come do their shift."
msgstr ""
-#: shifts/models.py:409 shifts/models.py:825
+#: shifts/models.py:415 shifts/models.py:831
#: shifts/templates/shifts/shift_detail.html:112
-#: shifts/templates/shifts/shift_template_detail.html:46
+#: shifts/templates/shifts/shift_template_detail.html:51
msgid "Chosen time"
msgstr "Ausgewählte Uhrzeit"
-#: shifts/models.py:411
+#: shifts/models.py:417
msgid "This shift lets you choose at what time you come during the day of the shift. In order to help organising the attendance, please specify when you expect to come.Setting or updating this field will set the time for all individual shifts generated from this ABCD shift.You can update the time of a single shift individually and at any time on the shift page."
msgstr ""
-#: shifts/models.py:495
+#: shifts/models.py:501
msgid "Number of required attendances"
msgstr "Anzahl notwendiger Teilnehmender"
-#: shifts/models.py:504
+#: shifts/models.py:510
msgid "Is shown on the shift page below the title"
msgstr ""
-#: shifts/models.py:524 shifts/models.py:530
+#: shifts/models.py:530 shifts/models.py:536
msgid "If 'flexible time' is enabled, then the time component is ignored"
msgstr ""
-#: shifts/models.py:827
+#: shifts/models.py:833
msgid "This shift lets you choose at what time you come during the day of the shift. In order to help organising the attendance, please specify when you expect to come."
msgstr "Diese Schicht ermöglicht dir auszusuchen, wann du kommen magst. Um die Planung zu erleichtern, gib bitte deine erwartete Ankunftszeit an."
-#: shifts/models.py:935 shifts/templates/shifts/shift_detail.html:308
+#: shifts/models.py:941 shifts/templates/shifts/shift_detail.html:308
#: shifts/templates/shifts/shift_detail_printable.html:52
msgid "Missed"
msgstr "Nicht erschienen"
-#: shifts/models.py:936 shifts/templates/shifts/shift_day_printable.html:216
+#: shifts/models.py:942 shifts/templates/shifts/shift_day_printable.html:216
#: shifts/templates/shifts/shift_day_printable.html:281
#: shifts/templates/shifts/shift_day_printable.html:283
#: shifts/templates/shifts/shift_detail.html:338
@@ -3230,66 +3234,66 @@ msgstr "Nicht erschienen"
msgid "Excused"
msgstr "Entschuldigt"
-#: shifts/models.py:937 shifts/templates/shifts/shift_detail.html:346
+#: shifts/models.py:943 shifts/templates/shifts/shift_detail.html:346
msgid "Cancelled"
msgstr "Abgesagt"
-#: shifts/models.py:938 shifts/templates/shifts/shift_day_printable.html:264
+#: shifts/models.py:944 shifts/templates/shifts/shift_day_printable.html:264
#: shifts/templates/shifts/shift_detail.html:330
#: shifts/templates/shifts/shift_detail_printable.html:94
#: shifts/templates/shifts/shift_filters.html:83
msgid "Looking for a stand-in"
msgstr "Sucht Vertretung"
-#: shifts/models.py:971
+#: shifts/models.py:977
msgid "🏠 ABCD"
msgstr "🏠 ABCD"
-#: shifts/models.py:972
+#: shifts/models.py:978
msgid "✈ Flying"
msgstr "✈ Fliegend"
-#: shifts/models.py:973
+#: shifts/models.py:979
msgid "❄ Frozen"
msgstr "❄ Eingefroren"
-#: shifts/models.py:1004
+#: shifts/models.py:1010
msgid "Is frozen"
msgstr "Ist eingefroren"
-#: shifts/models.py:1178
+#: shifts/models.py:1184
msgid "Cycle start date"
msgstr "Anfangsdatum"
-#: shifts/models.py:1199
+#: shifts/models.py:1205
msgid "Shift is almost full, only one spot left."
msgstr "Die Schicht ist fast voll, es ist nur noch ein Platz übrig."
-#: shifts/models.py:1200
+#: shifts/models.py:1206
msgid "Shift is full now."
msgstr "Die Schicht ist jetzt voll."
-#: shifts/models.py:1201
+#: shifts/models.py:1207
msgid "The Shift is understaffed!"
msgstr "Die Schicht ist jetzt unterbesetzt."
-#: shifts/models.py:1202
+#: shifts/models.py:1208
msgid "Shift stable: not understaffed, not fully staffed."
msgstr "Entwarnung. Die schicht ist nicht länger unterbesetzt, aber es noch Platz übrig"
-#: shifts/models.py:1204
+#: shifts/models.py:1210
msgid "One new attendance or more registered, but the shift is neither understaffed nor full or almost full."
msgstr "Ein Mitglied oder mehr hat sich registriert, aber die Schicht ist weder unterbesetzt noch (fast) voll"
-#: shifts/models.py:1207
+#: shifts/models.py:1213
msgid "One attendance or more un-registered, but the shift is neither understaffed nor full or almost full."
msgstr "Ein Mitglied oder mehr hat sich abgemeldet, aber die Schicht ist weder unterbesetzt noch (fast) voll"
-#: shifts/models.py:1210
+#: shifts/models.py:1216
msgid "The Shift Coordinator has unregistered"
msgstr "Ein Teamleiter hat sich abgemeldet"
-#: shifts/models.py:1213
+#: shifts/models.py:1219
msgid "A Shift Coordinator has registered"
msgstr "Ein Teamleiter hat sich angemeldet"
@@ -4112,7 +4116,7 @@ msgstr "Flexible Arbeitszeit nicht angegeben"
#: shifts/templates/shifts/shift_day_printable.html:259
#: shifts/templates/shifts/shift_detail.html:139
#: shifts/templates/shifts/shift_detail_printable.html:90
-#: shifts/templates/shifts/shift_template_detail.html:68
+#: shifts/templates/shifts/shift_template_detail.html:73
msgid "Shift partner: "
msgstr "Schicht-Partner: "
@@ -4176,12 +4180,12 @@ msgid "Number"
msgstr "Nummer"
#: shifts/templates/shifts/shift_detail.html:106
-#: shifts/templates/shifts/shift_template_detail.html:42
+#: shifts/templates/shifts/shift_template_detail.html:47
msgid "Details"
msgstr "Details"
#: shifts/templates/shifts/shift_detail.html:107
-#: shifts/templates/shifts/shift_template_detail.html:44
+#: shifts/templates/shifts/shift_template_detail.html:49
msgid "Registered user"
msgstr "Angemeldete*r Nutzer*in"
@@ -4194,7 +4198,7 @@ msgid "Do you meet the requirements?"
msgstr "Erfüllst du die Voraussetzungen?"
#: shifts/templates/shifts/shift_detail.html:115
-#: shifts/templates/shifts/shift_template_detail.html:49
+#: shifts/templates/shifts/shift_template_detail.html:54
msgid "Member-Office actions"
msgstr "Mitgliederbüro Aktionen"
@@ -4300,7 +4304,7 @@ msgstr ""
" "
#: shifts/templates/shifts/shift_detail.html:271
-#: shifts/templates/shifts/shift_template_detail.html:99
+#: shifts/templates/shifts/shift_template_detail.html:104
msgid "Not specified"
msgstr ""
@@ -4429,23 +4433,29 @@ msgstr ""
msgid "Duplicate"
msgstr "Dopplung"
-#: shifts/templates/shifts/shift_template_detail.html:38
+#: shifts/templates/shifts/shift_template_detail.html:34
+#, fuzzy
+#| msgid "Pay out end date"
+msgid "Set end date"
+msgstr "Auszahlungsende"
+
+#: shifts/templates/shifts/shift_template_detail.html:43
msgid "List of slots for this ABCD shifts"
msgstr "Liste des Slots für diese ABCD-Schicht"
-#: shifts/templates/shifts/shift_template_detail.html:43
+#: shifts/templates/shifts/shift_template_detail.html:48
msgid "Requirements"
msgstr ""
-#: shifts/templates/shifts/shift_template_detail.html:77
+#: shifts/templates/shifts/shift_template_detail.html:82
msgid "Unregister"
msgstr "Abmelden"
-#: shifts/templates/shifts/shift_template_detail.html:126
+#: shifts/templates/shifts/shift_template_detail.html:131
msgid "Future generated Shifts"
msgstr "Zukünftige erstellte Schichten"
-#: shifts/templates/shifts/shift_template_detail.html:136
+#: shifts/templates/shifts/shift_template_detail.html:141
msgid "Past generated Shifts"
msgstr "Vergangene Schichten"
@@ -4484,6 +4494,32 @@ msgstr ""
msgid "Calendar of ABCD shifts"
msgstr "Kalender der ABCD-Schichten"
+#: shifts/templates/shifts/shift_template_set_end_date.html:7
+#: shifts/templates/shifts/shift_template_set_end_date.html:11
+#, fuzzy
+#| msgid "Pay out end date"
+msgid "Set end date for"
+msgstr "Auszahlungsende"
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:17
+msgid "Warning"
+msgstr ""
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:18
+msgid "All shifts generated from this ABCD-shift after the selected date will be cancelled. Registered members will be notified."
+msgstr ""
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:22
+#, fuzzy
+#| msgid "Set shift attendance to"
+msgid "Set end date and cancel shifts"
+msgstr "Ändere den Schichtstatus zu"
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:25
+#: shifts/templates/shifts/user_shifts_overview_tag.html:177
+msgid "Cancel"
+msgstr "Abmelden"
+
#: shifts/templates/shifts/shiftexemption_list.html:38
msgid "Create shift exemption"
msgstr "Schicht-Befreiung erzeugen"
@@ -4515,7 +4551,7 @@ msgid "Recurring Shift Watches"
msgstr "Wiederholende Schichtbeobachtungen"
#: shifts/templates/shifts/shiftwatch_overview.html:25
-#: shifts/views/views.py:424
+#: shifts/views/views.py:470
msgid "Create a rule for recurring Shift Watches"
msgstr "Erstelle eine Regel für sich wiederholende Schichtbeobachtungen"
@@ -4762,10 +4798,6 @@ msgstr "Solidaritäts-Schicht spenden"
msgid "One of your banked shifts will be donated as a solidarity shift. Do you want to continue?"
msgstr "Eine deiner gearbeiteten Schichten wird als Solidaritäts-Schicht gespendet. Möchtest du fortfahren?"
-#: shifts/templates/shifts/user_shifts_overview_tag.html:177
-msgid "Cancel"
-msgstr "Abmelden"
-
#: shifts/templates/shifts/user_shifts_overview_tag.html:180
msgid "Confirm"
msgstr ""
@@ -4853,7 +4885,7 @@ msgid "No watched shifts"
msgstr "Keine beobachteten Schichten"
#: shifts/templatetags/shifts.py:70 shifts/templatetags/shifts.py:175
-#: shifts/views/views.py:152
+#: shifts/views/views.py:156
msgid "General"
msgstr "Allgemein"
@@ -4952,27 +4984,31 @@ msgstr "Es konnte keine vollendete Schicht gefunden werden, die als Solidarität
msgid "Solidarity Shift given. Account Balance debited with -1."
msgstr "Die Solidaritätsschicht wurde vergeben. Von deinem Kontostand wird nun eine Schicht abgezogen."
-#: shifts/views/views.py:132 shifts/views/views.py:137
+#: shifts/views/views.py:136 shifts/views/views.py:141
#, python-format
msgid "Edit user shift data: %(name)s"
msgstr "Bearbeite Nutzer*in-Schichtdaten: %(name)s"
-#: shifts/views/views.py:205
+#: shifts/views/views.py:209
#, python-format
msgid "Shift account: %(name)s"
msgstr "Schichtkonto-Protokoll für: %(name)s"
-#: shifts/views/views.py:211
+#: shifts/views/views.py:215
#, fuzzy, python-format
#| msgid "Create manual shift account entry for: %(link)s"
msgid "Create manual shift account entry for: %(link)s"
msgstr "Erzeuge Schicht-Kontoeintrag für: %(link)s"
-#: shifts/views/views.py:362
+#: shifts/views/views.py:332
+msgid "Shift template was successfully cancelled"
+msgstr ""
+
+#: shifts/views/views.py:408
msgid "Frozen statuses updated."
msgstr ""
-#: shifts/views/views.py:427
+#: shifts/views/views.py:473
#, python-format
msgid "Please select either %(shift_template_group)s and/or weekdays, or alternatively %(shift_templates)s."
msgstr ""
From 122758edcf1dfcb2428e0dda4f3cdd45f7bc1b28 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Sat, 18 Apr 2026 08:56:54 +0200
Subject: [PATCH 03/14] init TestShiftTemplateEndView
---
.../tests/test_shifttemplateenddateview.py | 88 +++++++++++++++++++
tapir/shifts/views/views.py | 10 +--
2 files changed, 93 insertions(+), 5 deletions(-)
create mode 100644 tapir/shifts/tests/test_shifttemplateenddateview.py
diff --git a/tapir/shifts/tests/test_shifttemplateenddateview.py b/tapir/shifts/tests/test_shifttemplateenddateview.py
new file mode 100644
index 000000000..f014734bf
--- /dev/null
+++ b/tapir/shifts/tests/test_shifttemplateenddateview.py
@@ -0,0 +1,88 @@
+import datetime
+
+from django.contrib.messages import get_messages
+from django.urls import reverse
+from django.utils import timezone
+
+from tapir.accounts.tests.factories.factories import TapirUserFactory
+from tapir.shifts.tests.factories import ShiftTemplateFactory
+from tapir.shifts.tests.utils import register_user_to_shift_template
+from tapir.utils.tests_utils import TapirFactoryTestBase
+
+
+class TestShiftTemplateEndView(TapirFactoryTestBase):
+
+ def setUp(self):
+ super().setUp()
+ self.shift_template = ShiftTemplateFactory.create()
+ self.url = reverse(
+ "shifts:shift_template_set_end_date", kwargs={"pk": self.shift_template.pk}
+ )
+
+ def test_shiftTemplate_setEndDate_futureShiftsAfterEndDateAreCancelled(self):
+ self.login_as_employee()
+
+ user = TapirUserFactory.create(is_in_member_office=False)
+ register_user_to_shift_template(self.client, user, self.shift_template)
+
+ today = timezone.now().today()
+ shift_1 = self.shift_template.create_shift_if_necessary(
+ today + datetime.timedelta(days=7)
+ )
+ shift_2 = self.shift_template.create_shift_if_necessary(
+ today + datetime.timedelta(days=14)
+ )
+ shift_3 = self.shift_template.create_shift_if_necessary(
+ today + datetime.timedelta(days=21)
+ )
+
+ end_date = today + datetime.timedelta(days=14)
+ cancellation_reason = "Shift Template ended"
+
+ response = self.client.post(
+ self.url,
+ {
+ "end_date": end_date.strftime("%Y-%m-%d"),
+ "cancellation_reason": cancellation_reason,
+ },
+ )
+
+ self.assertRedirects(
+ response,
+ reverse(
+ "shifts:shift_template_detail", kwargs={"pk": self.shift_template.pk}
+ ),
+ )
+
+ self.shift_template.refresh_from_db()
+ shift_1.refresh_from_db()
+ shift_2.refresh_from_db()
+ shift_3.refresh_from_db()
+
+ self.assertEqual(self.shift_template.end_date, end_date.date())
+
+ self.assertFalse(shift_1.cancelled)
+ self.assertFalse(shift_2.cancelled)
+
+ self.assertTrue(shift_3.cancelled)
+ self.assertEqual(shift_3.cancelled_reason, cancellation_reason)
+
+ # def test_shiftTemplate_sendEndDateAfterAllShifts_noShiftIsCancelled(self):
+ # self.login_as_employee()
+ # today = timezone.now().today()
+ # end_date = today + datetime.timedelta(days=365)
+ # cancellation_reason = "Shift Template ended"
+ #
+ # response = self.client.post(
+ # self.url,
+ # {
+ # "end_date": end_date.strftime("%Y-%m-%d"),
+ # "cancellation_reason": cancellation_reason,
+ # },
+ # )
+ #
+ # self.shift_template.refresh_from_db()
+ # self.assertEqual(self.shift_template.end_date, end_date.date())
+ #
+ # msgs = list(get_messages(response.wsgi_request))
+ # self.assertGreater(len(msgs), 0)
diff --git a/tapir/shifts/views/views.py b/tapir/shifts/views/views.py
index 8b61ffcc0..9dd185355 100644
--- a/tapir/shifts/views/views.py
+++ b/tapir/shifts/views/views.py
@@ -327,12 +327,12 @@ def form_valid(self, form):
shift.cancelled_reason = cancellation_reason
ShiftCancellationService.cancel(shift)
- messages.success(
- self.request,
- _("Shift template was successfully cancelled"),
- )
+ messages.success(
+ self.request,
+ _("Shift template was successfully cancelled"),
+ )
- return response
+ return response
class ShiftUserDataTable(django_tables2.Table):
From 46547b9b0f2109daddf3309cca6358ebb7c71509 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Sat, 18 Apr 2026 09:12:44 +0200
Subject: [PATCH 04/14]
test_createShiftForGroup_endDate_noShiftsCreatedPastEndDate
---
.../test_create_shifts_for_group.py | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/tapir/shifts/tests/services/shift_generator/test_create_shifts_for_group.py b/tapir/shifts/tests/services/shift_generator/test_create_shifts_for_group.py
index f6fd77917..387dbaf10 100644
--- a/tapir/shifts/tests/services/shift_generator/test_create_shifts_for_group.py
+++ b/tapir/shifts/tests/services/shift_generator/test_create_shifts_for_group.py
@@ -113,3 +113,22 @@ def test_createShiftsForGroup_withoutHolidayCancellation_doesntCancelsHolidays(
)
self.assertFalse(shift.cancelled)
self.assertIsNone(shift.cancelled_reason)
+
+ def test_createShiftForGroup_endDate_noShiftsCreatedPastEndDate(self):
+ group_a = ShiftTemplateGroup.objects.create(name="A")
+
+ template_with_future_end_date = ShiftTemplateFactory.create(
+ group=group_a, end_date=datetime.date(2025, 11, 20)
+ )
+
+ # should be created
+ ShiftGenerator.create_shifts_for_group(
+ at_date=datetime.date(2025, 11, 10), group=group_a
+ )
+
+ # should not be created
+ ShiftGenerator.create_shifts_for_group(
+ at_date=datetime.date(2025, 11, 24), group=group_a
+ )
+
+ self.assertEqual(1, template_with_future_end_date.generated_shifts.count())
From ea0635dd05defb9d47d308396af0d6a5b8686f22 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Sat, 18 Apr 2026 09:42:26 +0200
Subject: [PATCH 05/14] fix test
---
.../tests/test_shifttemplateenddateview.py | 57 +++++++++++--------
1 file changed, 34 insertions(+), 23 deletions(-)
diff --git a/tapir/shifts/tests/test_shifttemplateenddateview.py b/tapir/shifts/tests/test_shifttemplateenddateview.py
index f014734bf..e198078af 100644
--- a/tapir/shifts/tests/test_shifttemplateenddateview.py
+++ b/tapir/shifts/tests/test_shifttemplateenddateview.py
@@ -3,6 +3,7 @@
from django.contrib.messages import get_messages
from django.urls import reverse
from django.utils import timezone
+from django_extensions.jobs import weekly
from tapir.accounts.tests.factories.factories import TapirUserFactory
from tapir.shifts.tests.factories import ShiftTemplateFactory
@@ -14,18 +15,22 @@ class TestShiftTemplateEndView(TapirFactoryTestBase):
def setUp(self):
super().setUp()
- self.shift_template = ShiftTemplateFactory.create()
+ self.shift_template = ShiftTemplateFactory.create(
+ start_date=timezone.now().date(), weekday=0
+ )
self.url = reverse(
"shifts:shift_template_set_end_date", kwargs={"pk": self.shift_template.pk}
)
- def test_shiftTemplate_setEndDate_futureShiftsAfterEndDateAreCancelled(self):
+ def test_shiftTemplate_setEndDateInBetween_futureShiftsAfterEndDateAreCancelled(
+ self,
+ ):
self.login_as_employee()
user = TapirUserFactory.create(is_in_member_office=False)
register_user_to_shift_template(self.client, user, self.shift_template)
- today = timezone.now().today()
+ today = timezone.now().date()
shift_1 = self.shift_template.create_shift_if_necessary(
today + datetime.timedelta(days=7)
)
@@ -59,7 +64,7 @@ def test_shiftTemplate_setEndDate_futureShiftsAfterEndDateAreCancelled(self):
shift_2.refresh_from_db()
shift_3.refresh_from_db()
- self.assertEqual(self.shift_template.end_date, end_date.date())
+ self.assertEqual(self.shift_template.end_date, end_date)
self.assertFalse(shift_1.cancelled)
self.assertFalse(shift_2.cancelled)
@@ -67,22 +72,28 @@ def test_shiftTemplate_setEndDate_futureShiftsAfterEndDateAreCancelled(self):
self.assertTrue(shift_3.cancelled)
self.assertEqual(shift_3.cancelled_reason, cancellation_reason)
- # def test_shiftTemplate_sendEndDateAfterAllShifts_noShiftIsCancelled(self):
- # self.login_as_employee()
- # today = timezone.now().today()
- # end_date = today + datetime.timedelta(days=365)
- # cancellation_reason = "Shift Template ended"
- #
- # response = self.client.post(
- # self.url,
- # {
- # "end_date": end_date.strftime("%Y-%m-%d"),
- # "cancellation_reason": cancellation_reason,
- # },
- # )
- #
- # self.shift_template.refresh_from_db()
- # self.assertEqual(self.shift_template.end_date, end_date.date())
- #
- # msgs = list(get_messages(response.wsgi_request))
- # self.assertGreater(len(msgs), 0)
+ def test_shiftTemplate_sendEndDateAfterAllShifts_noShiftIsCancelled(self):
+ self.login_as_employee()
+ today = timezone.now().date()
+ end_date = today + datetime.timedelta(days=365)
+ cancellation_reason = "Shift Template ended"
+ shift = self.shift_template.create_shift_if_necessary(
+ today + datetime.timedelta(days=7)
+ )
+
+ response = self.client.post(
+ self.url,
+ {
+ "end_date": end_date.strftime("%Y-%m-%d"),
+ "cancellation_reason": cancellation_reason,
+ },
+ )
+
+ self.shift_template.refresh_from_db()
+ shift.refresh_from_db()
+ self.assertEqual(self.shift_template.end_date, end_date)
+
+ self.assertFalse(shift.cancelled)
+
+ msgs = list(get_messages(response.wsgi_request))
+ self.assertGreater(len(msgs), 0)
From 5e756c0e8b85ba8288660d441df7458436a11275 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Sat, 18 Apr 2026 09:54:51 +0200
Subject: [PATCH 06/14] end_date should not be before start date
---
tapir/shifts/forms.py | 8 +++++++
.../tests/test_shifttemplateenddateview.py | 21 +++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/tapir/shifts/forms.py b/tapir/shifts/forms.py
index 0f16ea153..d454bc8de 100644
--- a/tapir/shifts/forms.py
+++ b/tapir/shifts/forms.py
@@ -471,6 +471,14 @@ def __init__(self, shift_template=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["end_date"].required = True
+ def clean_end_date(self):
+ if (
+ self.cleaned_data["end_date"]
+ and self.cleaned_data["end_date"] < self.instance.start_date
+ ):
+ raise ValidationError(_("The end date must be later than the start date."))
+ return self.cleaned_data["end_date"]
+
class CreateShiftAccountEntryForm(forms.ModelForm):
class Meta:
diff --git a/tapir/shifts/tests/test_shifttemplateenddateview.py b/tapir/shifts/tests/test_shifttemplateenddateview.py
index e198078af..cc45960fe 100644
--- a/tapir/shifts/tests/test_shifttemplateenddateview.py
+++ b/tapir/shifts/tests/test_shifttemplateenddateview.py
@@ -97,3 +97,24 @@ def test_shiftTemplate_sendEndDateAfterAllShifts_noShiftIsCancelled(self):
msgs = list(get_messages(response.wsgi_request))
self.assertGreater(len(msgs), 0)
+
+ def test_shiftTemplate_sendEndDate_endDateBeforeStartDate_showsValidationError(
+ self,
+ ):
+ self.login_as_employee()
+
+ end_date = self.shift_template.start_date - datetime.timedelta(days=7)
+
+ response = self.client.post(
+ self.url,
+ {
+ "end_date": end_date.strftime("%Y-%m-%d"),
+ "cancellation_reason": "Test",
+ },
+ )
+
+ self.assertEqual(response.status_code, 200)
+ self.assertIn("end_date", response.context["form"].errors)
+
+ self.shift_template.refresh_from_db()
+ self.assertIsNone(self.shift_template.end_date)
From 3db24b4d3ad09505817134c131e2acfe78bcc704 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Sat, 18 Apr 2026 09:55:22 +0200
Subject: [PATCH 07/14] translation
---
.../locale/de/LC_MESSAGES/django.po | 40 +++++++++----------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po
index e5998bd4e..137d692ee 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-04-18 07:38+0200\n"
+"POT-Creation-Date: 2026-04-18 09:55+0200\n"
"PO-Revision-Date: 2025-07-07 13:06+0000\n"
"Last-Translator: Weblate Admin \n"
"Language-Team: German \n"
@@ -644,7 +644,7 @@ msgstr "Wird normalerweise leer gelassen. Das Datum kann in der Zukunft liegen,
msgid "Number of shares to create"
msgstr "Anzahl zu erstellender Anteile"
-#: coop/forms.py:67
+#: coop/forms.py:67 shifts/forms.py:479
msgid "The end date must be later than the start date."
msgstr "Das Enddatum muss später als das Start-Datum sein"
@@ -2563,7 +2563,7 @@ msgstr "Hat Qualifikation"
msgid "Does not have qualification"
msgstr "Hat die Qualifikation nicht"
-#: coop/views/shareowner.py:647 shifts/forms.py:790
+#: coop/views/shareowner.py:647 shifts/forms.py:798
msgid "ABCD Week"
msgstr "ABCD-Woche"
@@ -3038,78 +3038,78 @@ msgstr "Das ausgewählte Mitglied muss ein investierendes Mitglied sein."
msgid "This member is registered to at least one ABCD shift. Please confirm the change of attendance mode with the checkbox below."
msgstr ""
-#: shifts/forms.py:463 shifts/forms.py:621
+#: shifts/forms.py:463 shifts/forms.py:629
msgid "Cancellation Reason"
msgstr "Grund der Absage"
-#: shifts/forms.py:510
+#: shifts/forms.py:518
msgid "I have read the warning about the cancelled attendances and confirm that the exemption should be created"
msgstr "Ich habe die Warnung über die abgesagte Schicht-Anwesenheit gelesen und bestätige, dass die Befreiung erzeugt werden soll"
-#: shifts/forms.py:517
+#: shifts/forms.py:525
msgid "I have read the warning about the cancelled ABCD attendances and confirm that the exemption should be created"
msgstr "Ich habe die Warnung über die abgebrochene ABCD-Teilnahme gelesen und bestätige, dass die Befreiung erzeugt werden soll"
-#: shifts/forms.py:575
+#: shifts/forms.py:583
#, python-format
msgid "The user will be unregistered from the following ABCD shifts because the exemption is longer than %(number_of_cycles)s cycles: %(attendances_display)s "
msgstr "Das Mitglied wird von den folgenden ABCD-Schichten abgemeldet, weil die Befreiung länger als %(number_of_cycles)s Schichtzyklen ist: %(attendances_display)s "
-#: shifts/forms.py:596
+#: shifts/forms.py:604
msgid "This shift has been deleted. It is not possible to cancel it."
msgstr "Diese Schicht wurde bereits gelöscht. Es ist nicht möglich diese abzusagen."
-#: shifts/forms.py:607 shifts/templates/shifts/shift_detail.html:8
+#: shifts/forms.py:615 shifts/templates/shifts/shift_detail.html:8
#: shifts/templates/shifts/shift_detail.html:30
msgid "Shift"
msgstr "Schicht"
-#: shifts/forms.py:608
+#: shifts/forms.py:616
msgid "already cancelled"
msgstr "bereits bgesagt"
-#: shifts/forms.py:622
+#: shifts/forms.py:630
msgid "This reason will be applied to all cancelled shifts."
msgstr ""
-#: shifts/forms.py:650
+#: shifts/forms.py:658
msgid "I understand that updating this ABCD shift will update all the corresponding future shifts"
msgstr ""
-#: shifts/forms.py:669
+#: shifts/forms.py:677
msgid "ABCD-Week"
msgstr "ABCD-Woche"
-#: shifts/forms.py:673
+#: shifts/forms.py:681
msgid "Weekdays"
msgstr "Wochentage"
-#: shifts/forms.py:698
+#: shifts/forms.py:706
msgid "I understand that adding or editing a slot to this ABCD shift will affect all the corresponding future shifts"
msgstr ""
-#: shifts/forms.py:707
+#: shifts/forms.py:715
msgid "I understand that this will delete the shift exemption and create a membership pause"
msgstr ""
-#: shifts/forms.py:739 shifts/forms.py:795 shifts/views/views.py:425
+#: shifts/forms.py:747 shifts/forms.py:803 shifts/views/views.py:425
#: shifts/views/views.py:426
msgid "Shift changes you would like to be informed about"
msgstr "Schicht-Änderungen, bei denen du informiert werden möchtest"
-#: shifts/forms.py:784 shifts/templates/shifts/shift_template_detail.html:7
+#: shifts/forms.py:792 shifts/templates/shifts/shift_template_detail.html:7
#: shifts/templates/shifts/shift_template_detail.html:15
#: shifts/templates/shifts/user_shifts_overview_tag.html:31
#: shifts/templates/shifts/user_shifts_overview_tag.html:43
msgid "ABCD Shift"
msgstr "ABCD-Schicht"
-#: shifts/forms.py:801
+#: shifts/forms.py:809
#, python-format
msgid "If weekdays or %(shift_template_group)s are selected, %(shift_templates)s may not be selected, and vice versa."
msgstr ""
-#: shifts/forms.py:805
+#: shifts/forms.py:813
#, python-format
msgid "At least one of the fields (%(shift_templates)s, weekdays, or %(shift_template_group)s) must be selected."
msgstr ""
From 406fc370f3e44862281660004097807729688be7 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Sun, 14 Jun 2026 19:28:05 +0200
Subject: [PATCH 08/14] translation
---
.../locale/de/LC_MESSAGES/django.po | 186 +++++++++++-------
1 file changed, 111 insertions(+), 75 deletions(-)
diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po
index ce1f84ca4..f7c373652 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-06-09 08:36+0200\n"
+"POT-Creation-Date: 2026-06-14 19:27+0200\n"
"PO-Revision-Date: 2025-07-07 13:06+0000\n"
"Last-Translator: Weblate Admin \n"
"Language-Team: German \n"
@@ -343,7 +343,7 @@ msgstr "Benutzername bearbeiten"
#: core/templates/core/featureflag_list.html:30
#: shifts/templates/shifts/shift_detail.html:61
#: shifts/templates/shifts/shift_template_detail.html:29
-#: shifts/templates/shifts/shift_template_detail.html:117
+#: shifts/templates/shifts/shift_template_detail.html:122
#: shifts/templates/shifts/user_shifts_overview_tag.html:14
msgid "Edit"
msgstr "Bearbeiten"
@@ -652,7 +652,7 @@ msgstr "Wird normalerweise leer gelassen. Das Datum kann in der Zukunft liegen,
msgid "Number of shares to create"
msgstr "Anzahl zu erstellender Anteile"
-#: coop/forms.py:67
+#: coop/forms.py:67 shifts/forms.py:478
msgid "The end date must be later than the start date."
msgstr "Das Enddatum muss später als das Start-Datum sein"
@@ -1113,7 +1113,7 @@ msgstr "Bewerber*in erzeugen"
#: shifts/templates/shifts/register_user_to_shift_slot.html:27
#: shifts/templates/shifts/register_user_to_shift_slot_template.html:26
#: shifts/templates/shifts/shift_detail.html:243
-#: shifts/templates/shifts/shift_template_detail.html:88
+#: shifts/templates/shifts/shift_template_detail.html:93
msgid "Register"
msgstr "Anmelden"
@@ -2089,6 +2089,7 @@ msgid "Submit"
msgstr "Abschicken"
#: coop/templates/coop/extra_share_request.html:92
+#: shifts/templates/shifts/shift_template_set_end_date.html:25
#: shifts/templates/shifts/user_shifts_overview_tag.html:177
msgid "Cancel"
msgstr "Abmelden"
@@ -2275,7 +2276,7 @@ msgstr ""
" "
#: coop/templates/coop/membershipresignation_detail.html:61
-#: shifts/models.py:535
+#: shifts/models.py:541
msgid "Cancellation reason"
msgstr "Grund der Kündigung"
@@ -2522,7 +2523,7 @@ msgstr ""
" "
#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:56
-#: shifts/models.py:933 shifts/templates/shifts/shift_day_printable.html:214
+#: shifts/models.py:939 shifts/templates/shifts/shift_day_printable.html:214
#: shifts/templates/shifts/shift_day_printable.html:276
#: shifts/templates/shifts/shift_detail.html:298
#: shifts/templates/shifts/shift_detail_printable.html:51
@@ -2530,7 +2531,7 @@ msgid "Attended"
msgstr "Teilgenommen"
#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:58
-#: shifts/models.py:932
+#: shifts/models.py:938
msgid "Pending"
msgstr "Ausstehend"
@@ -2703,7 +2704,7 @@ msgstr "Hat Qualifikation"
msgid "Does not have qualification"
msgstr "Hat die Qualifikation nicht"
-#: coop/views/shareowner.py:656 shifts/forms.py:788
+#: coop/views/shareowner.py:656 shifts/forms.py:809
msgid "ABCD Week"
msgstr "ABCD-Woche"
@@ -2836,8 +2837,8 @@ 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
+#: core/templates/core/email_list.html:39 shifts/models.py:508
+#: shifts/models.py:1077 shifts/templates/shifts/user_shift_account_log.html:29
msgid "Description"
msgstr "Beschreibung"
@@ -3182,86 +3183,86 @@ msgstr "Das ausgewählte Mitglied muss ein investierendes Mitglied sein."
msgid "This member is registered to at least one ABCD shift. Please confirm the change of attendance mode with the checkbox below."
msgstr ""
-#: shifts/forms.py:496
+#: shifts/forms.py:462 shifts/forms.py:628
+msgid "Cancellation Reason"
+msgstr "Grund der Absage"
+
+#: shifts/forms.py:517
msgid "I have read the warning about the cancelled attendances and confirm that the exemption should be created"
msgstr "Ich habe die Warnung über die abgesagte Schicht-Anwesenheit gelesen und bestätige, dass die Befreiung erzeugt werden soll"
-#: shifts/forms.py:503
+#: shifts/forms.py:524
msgid "I have read the warning about the cancelled ABCD attendances and confirm that the exemption should be created"
msgstr "Ich habe die Warnung über die abgebrochene ABCD-Teilnahme gelesen und bestätige, dass die Befreiung erzeugt werden soll"
-#: shifts/forms.py:561
+#: shifts/forms.py:582
#, python-format
msgid "The user will be unregistered from the following ABCD shifts because the exemption is longer than %(number_of_cycles)s cycles: %(attendances_display)s "
msgstr "Das Mitglied wird von den folgenden ABCD-Schichten abgemeldet, weil die Befreiung länger als %(number_of_cycles)s Schichtzyklen ist: %(attendances_display)s "
-#: shifts/forms.py:582
+#: shifts/forms.py:603
msgid "This shift has been deleted. It is not possible to cancel it."
msgstr "Diese Schicht wurde bereits gelöscht. Es ist nicht möglich diese abzusagen."
-#: shifts/forms.py:593 shifts/templates/shifts/shift_detail.html:8
+#: shifts/forms.py:614 shifts/templates/shifts/shift_detail.html:8
#: shifts/templates/shifts/shift_detail.html:30
msgid "Shift"
msgstr "Schicht"
-#: shifts/forms.py:594
+#: shifts/forms.py:615
msgid "already cancelled"
msgstr "bereits bgesagt"
-#: shifts/forms.py:607
-msgid "Cancellation Reason"
-msgstr "Grund der Absage"
-
-#: shifts/forms.py:608
+#: shifts/forms.py:629
msgid "This reason will be applied to all cancelled shifts."
msgstr ""
-#: shifts/forms.py:636
+#: shifts/forms.py:657
msgid "I understand that updating this ABCD shift will update all the corresponding future shifts"
msgstr ""
-#: shifts/forms.py:655
+#: shifts/forms.py:676
msgid "ABCD-Week"
msgstr "ABCD-Woche"
-#: shifts/forms.py:659
+#: shifts/forms.py:680
msgid "Weekdays"
msgstr "Wochentage"
-#: shifts/forms.py:684
+#: shifts/forms.py:705
msgid "I understand that adding or editing a slot to this ABCD shift will affect all the corresponding future shifts"
msgstr ""
-#: shifts/forms.py:693
+#: shifts/forms.py:714
msgid "I understand that this will delete the shift exemption and create a membership pause"
msgstr ""
-#: shifts/forms.py:725 shifts/forms.py:793 shifts/views/views.py:377
-#: shifts/views/views.py:378
+#: shifts/forms.py:746 shifts/forms.py:814 shifts/views/views.py:421
+#: shifts/views/views.py:422
msgid "Shift changes you would like to be informed about"
msgstr "Schicht-Änderungen, bei denen du informiert werden möchtest"
-#: shifts/forms.py:732
+#: shifts/forms.py:753
msgid "Notify me when these capabilities become available or unavailable"
msgstr ""
-#: shifts/forms.py:736
+#: shifts/forms.py:757
msgid "Get notified when someone with specific skills registers or unregisters"
msgstr ""
-#: shifts/forms.py:782 shifts/templates/shifts/shift_template_detail.html:7
+#: shifts/forms.py:803 shifts/templates/shifts/shift_template_detail.html:7
#: shifts/templates/shifts/shift_template_detail.html:15
#: shifts/templates/shifts/user_shifts_overview_tag.html:31
#: shifts/templates/shifts/user_shifts_overview_tag.html:43
msgid "ABCD Shift"
msgstr "ABCD-Schicht"
-#: shifts/forms.py:799
+#: shifts/forms.py:820
#, python-format
msgid "If weekdays or %(shift_template_group)s are selected, %(shift_templates)s may not be selected, and vice versa."
msgstr ""
-#: shifts/forms.py:803
+#: shifts/forms.py:824
#, python-format
msgid "At least one of the fields (%(shift_templates)s, weekdays, or %(shift_template_group)s) must be selected."
msgstr ""
@@ -3326,7 +3327,7 @@ msgstr "Mir ist klar, dass ich bei dieser Schicht möglicherweise schwere Gewich
msgid "I understand that I may need to work high, for example up a ladder. I do not suffer from fear of heights."
msgstr "Mir ist klar, dass ich möglicherweise in großer Höhe arbeiten muss, zum Beispiel auf einer Leiter. Ich leide nicht unter Höhenangst."
-#: shifts/models.py:166 shifts/models.py:496
+#: shifts/models.py:166 shifts/models.py:502
msgid "If there are less members registered to a shift than that number, it will be highlighted in the shift calendar. The number of required attendances can't be higher than the slots in the resp. shift."
msgstr "Wenn weniger Mitlieder als diese Nummer zur Schicht registriert sind, wird diese blau angezeigt. Die Anzahl der benltigten Mitglieder kann nicht höher sein als die Anzahl vorhandener Slots."
@@ -3334,47 +3335,51 @@ msgstr "Wenn weniger Mitlieder als diese Nummer zur Schicht registriert sind, wi
msgid "This determines from which date shifts should be generated from this ABCD shift."
msgstr ""
-#: shifts/models.py:181 shifts/models.py:510
+#: shifts/models.py:183
+msgid "All shifts after this date will be cancelled."
+msgstr ""
+
+#: shifts/models.py:186 shifts/models.py:516
#: shifts/templates/shifts/shift_block_tag.html:11
msgid "Flexible time"
msgstr "Zeit flexibel"
-#: shifts/models.py:183 shifts/models.py:512
+#: shifts/models.py:188 shifts/models.py:518
msgid "If enabled, members who register for that shift can choose themselves the time where they come do their shift."
msgstr ""
-#: shifts/models.py:408 shifts/models.py:824
+#: shifts/models.py:414 shifts/models.py:830
#: shifts/templates/shifts/shift_detail.html:112
-#: shifts/templates/shifts/shift_template_detail.html:46
+#: shifts/templates/shifts/shift_template_detail.html:51
msgid "Chosen time"
msgstr "Ausgewählte Uhrzeit"
-#: shifts/models.py:410
+#: shifts/models.py:416
msgid "This shift lets you choose at what time you come during the day of the shift. In order to help organising the attendance, please specify when you expect to come.Setting or updating this field will set the time for all individual shifts generated from this ABCD shift.You can update the time of a single shift individually and at any time on the shift page."
msgstr ""
-#: shifts/models.py:494
+#: shifts/models.py:500
msgid "Number of required attendances"
msgstr "Anzahl notwendiger Teilnehmender"
-#: shifts/models.py:503
+#: shifts/models.py:509
msgid "Is shown on the shift page below the title"
msgstr ""
-#: shifts/models.py:523 shifts/models.py:529
+#: shifts/models.py:529 shifts/models.py:535
msgid "If 'flexible time' is enabled, then the time component is ignored"
msgstr ""
-#: shifts/models.py:826
+#: shifts/models.py:832
msgid "This shift lets you choose at what time you come during the day of the shift. In order to help organising the attendance, please specify when you expect to come."
msgstr "Diese Schicht ermöglicht dir auszusuchen, wann du kommen magst. Um die Planung zu erleichtern, gib bitte deine erwartete Ankunftszeit an."
-#: shifts/models.py:934 shifts/templates/shifts/shift_detail.html:308
+#: shifts/models.py:940 shifts/templates/shifts/shift_detail.html:308
#: shifts/templates/shifts/shift_detail_printable.html:52
msgid "Missed"
msgstr "Nicht erschienen"
-#: shifts/models.py:935 shifts/templates/shifts/shift_day_printable.html:216
+#: shifts/models.py:941 shifts/templates/shifts/shift_day_printable.html:216
#: shifts/templates/shifts/shift_day_printable.html:281
#: shifts/templates/shifts/shift_day_printable.html:283
#: shifts/templates/shifts/shift_detail.html:338
@@ -3382,58 +3387,58 @@ msgstr "Nicht erschienen"
msgid "Excused"
msgstr "Entschuldigt"
-#: shifts/models.py:936 shifts/templates/shifts/shift_detail.html:346
+#: shifts/models.py:942 shifts/templates/shifts/shift_detail.html:346
msgid "Cancelled"
msgstr "Abgesagt"
-#: shifts/models.py:937 shifts/templates/shifts/shift_day_printable.html:264
+#: shifts/models.py:943 shifts/templates/shifts/shift_day_printable.html:264
#: shifts/templates/shifts/shift_detail.html:330
#: shifts/templates/shifts/shift_detail_printable.html:94
#: shifts/templates/shifts/shift_filters.html:83
msgid "Looking for a stand-in"
msgstr "Sucht Vertretung"
-#: shifts/models.py:970
+#: shifts/models.py:976
msgid "🏠 ABCD"
msgstr "🏠 ABCD"
-#: shifts/models.py:971
+#: shifts/models.py:977
msgid "✈ Flying"
msgstr "✈ Fliegend"
-#: shifts/models.py:972
+#: shifts/models.py:978
msgid "❄ Frozen"
msgstr "❄ Eingefroren"
-#: shifts/models.py:1003
+#: shifts/models.py:1009
msgid "Is frozen"
msgstr "Ist eingefroren"
-#: shifts/models.py:1177
+#: shifts/models.py:1183
msgid "Cycle start date"
msgstr "Anfangsdatum"
-#: shifts/models.py:1198
+#: shifts/models.py:1204
msgid "Shift is almost full, only one spot left."
msgstr "Die Schicht ist fast voll, es ist nur noch ein Platz übrig."
-#: shifts/models.py:1199
+#: shifts/models.py:1205
msgid "Shift is full now."
msgstr "Die Schicht ist jetzt voll."
-#: shifts/models.py:1200
+#: shifts/models.py:1206
msgid "The Shift is understaffed!"
msgstr "Die Schicht ist jetzt unterbesetzt."
-#: shifts/models.py:1201
+#: shifts/models.py:1207
msgid "Shift stable: not understaffed, not fully staffed."
msgstr "Entwarnung. Die schicht ist nicht länger unterbesetzt, aber es noch Platz übrig"
-#: shifts/models.py:1203
+#: shifts/models.py:1209
msgid "One new attendance or more registered, but the shift is neither understaffed nor full or almost full."
msgstr "Ein Mitglied oder mehr hat sich registriert, aber die Schicht ist weder unterbesetzt noch (fast) voll"
-#: shifts/models.py:1206
+#: shifts/models.py:1212
msgid "One attendance or more un-registered, but the shift is neither understaffed nor full or almost full."
msgstr "Ein Mitglied oder mehr hat sich abgemeldet, aber die Schicht ist weder unterbesetzt noch (fast) voll"
@@ -4256,7 +4261,7 @@ msgstr "Flexible Arbeitszeit nicht angegeben"
#: shifts/templates/shifts/shift_day_printable.html:259
#: shifts/templates/shifts/shift_detail.html:139
#: shifts/templates/shifts/shift_detail_printable.html:90
-#: shifts/templates/shifts/shift_template_detail.html:68
+#: shifts/templates/shifts/shift_template_detail.html:73
msgid "Shift partner: "
msgstr "Schicht-Partner: "
@@ -4320,12 +4325,12 @@ msgid "Number"
msgstr "Nummer"
#: shifts/templates/shifts/shift_detail.html:106
-#: shifts/templates/shifts/shift_template_detail.html:42
+#: shifts/templates/shifts/shift_template_detail.html:47
msgid "Details"
msgstr "Details"
#: shifts/templates/shifts/shift_detail.html:107
-#: shifts/templates/shifts/shift_template_detail.html:44
+#: shifts/templates/shifts/shift_template_detail.html:49
msgid "Registered user"
msgstr "Angemeldete*r Nutzer*in"
@@ -4338,7 +4343,7 @@ msgid "Do you meet the requirements?"
msgstr "Erfüllst du die Voraussetzungen?"
#: shifts/templates/shifts/shift_detail.html:115
-#: shifts/templates/shifts/shift_template_detail.html:49
+#: shifts/templates/shifts/shift_template_detail.html:54
msgid "Member-Office actions"
msgstr "Mitgliederbüro Aktionen"
@@ -4444,7 +4449,7 @@ msgstr ""
" "
#: shifts/templates/shifts/shift_detail.html:271
-#: shifts/templates/shifts/shift_template_detail.html:99
+#: shifts/templates/shifts/shift_template_detail.html:104
msgid "Not specified"
msgstr ""
@@ -4573,23 +4578,29 @@ msgstr ""
msgid "Duplicate"
msgstr "Dopplung"
-#: shifts/templates/shifts/shift_template_detail.html:38
+#: shifts/templates/shifts/shift_template_detail.html:34
+#, fuzzy
+#| msgid "Pay out end date"
+msgid "Set end date"
+msgstr "Auszahlungsende"
+
+#: shifts/templates/shifts/shift_template_detail.html:43
msgid "List of slots for this ABCD shifts"
msgstr "Liste des Slots für diese ABCD-Schicht"
-#: shifts/templates/shifts/shift_template_detail.html:43
+#: shifts/templates/shifts/shift_template_detail.html:48
msgid "Requirements"
msgstr ""
-#: shifts/templates/shifts/shift_template_detail.html:77
+#: shifts/templates/shifts/shift_template_detail.html:82
msgid "Unregister"
msgstr "Abmelden"
-#: shifts/templates/shifts/shift_template_detail.html:126
+#: shifts/templates/shifts/shift_template_detail.html:131
msgid "Future generated Shifts"
msgstr "Zukünftige erstellte Schichten"
-#: shifts/templates/shifts/shift_template_detail.html:136
+#: shifts/templates/shifts/shift_template_detail.html:141
msgid "Past generated Shifts"
msgstr "Vergangene Schichten"
@@ -4628,6 +4639,27 @@ msgstr ""
msgid "Calendar of ABCD shifts"
msgstr "Kalender der ABCD-Schichten"
+#: shifts/templates/shifts/shift_template_set_end_date.html:7
+#: shifts/templates/shifts/shift_template_set_end_date.html:11
+#, fuzzy
+#| msgid "Pay out end date"
+msgid "Set end date for"
+msgstr "Auszahlungsende"
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:17
+msgid "Warning"
+msgstr ""
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:18
+msgid "All shifts generated from this ABCD-shift after the selected date will be cancelled. Registered members will be notified."
+msgstr ""
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:22
+#, fuzzy
+#| msgid "Set shift attendance to"
+msgid "Set end date and cancel shifts"
+msgstr "Ändere den Schichtstatus zu"
+
#: shifts/templates/shifts/shiftexemption_list.html:38
msgid "Create shift exemption"
msgstr "Schicht-Befreiung erzeugen"
@@ -4659,7 +4691,7 @@ msgid "Recurring Shift Watches"
msgstr "Wiederholende Schichtbeobachtungen"
#: shifts/templates/shifts/shiftwatch_overview.html:25
-#: shifts/views/views.py:422
+#: shifts/views/views.py:466
msgid "Create a rule for recurring Shift Watches"
msgstr "Erstelle eine Regel für sich wiederholende Schichtbeobachtungen"
@@ -4993,7 +5025,7 @@ msgid "No watched shifts"
msgstr "Keine beobachteten Schichten"
#: shifts/templatetags/shifts.py:69 shifts/templatetags/shifts.py:174
-#: shifts/views/views.py:150
+#: shifts/views/views.py:152
msgid "General"
msgstr "Allgemein"
@@ -5092,27 +5124,31 @@ msgstr "Es konnte keine vollendete Schicht gefunden werden, die als Solidarität
msgid "Solidarity Shift given. Account Balance debited with -1."
msgstr "Die Solidaritätsschicht wurde vergeben. Von deinem Kontostand wird nun eine Schicht abgezogen."
-#: shifts/views/views.py:130 shifts/views/views.py:135
+#: shifts/views/views.py:132 shifts/views/views.py:137
#, python-format
msgid "Edit user shift data: %(name)s"
msgstr "Bearbeite Nutzer*in-Schichtdaten: %(name)s"
-#: shifts/views/views.py:203
+#: shifts/views/views.py:205
#, python-format
msgid "Shift account: %(name)s"
msgstr "Schichtkonto-Protokoll für: %(name)s"
-#: shifts/views/views.py:209
+#: shifts/views/views.py:211
#, fuzzy, python-format
#| msgid "Create manual shift account entry for: %(link)s"
msgid "Create manual shift account entry for: %(link)s"
msgstr "Erzeuge Schicht-Kontoeintrag für: %(link)s"
-#: shifts/views/views.py:360
+#: shifts/views/views.py:328
+msgid "Shift template was successfully cancelled"
+msgstr ""
+
+#: shifts/views/views.py:404
msgid "Frozen statuses updated."
msgstr ""
-#: shifts/views/views.py:425
+#: shifts/views/views.py:469
#, python-format
msgid "Please select either %(shift_template_group)s and/or weekdays, or alternatively %(shift_templates)s."
msgstr ""
From 0fad0d059f04e99aeac7c61ef4e6accc3c97ed93 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Sun, 14 Jun 2026 19:38:12 +0200
Subject: [PATCH 09/14] fix migration
---
...ifttemplate_end_date.py => 0076_shifttemplate_end_date.py} | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
rename tapir/shifts/migrations/{0075_shifttemplate_end_date.py => 0076_shifttemplate_end_date.py} (78%)
diff --git a/tapir/shifts/migrations/0075_shifttemplate_end_date.py b/tapir/shifts/migrations/0076_shifttemplate_end_date.py
similarity index 78%
rename from tapir/shifts/migrations/0075_shifttemplate_end_date.py
rename to tapir/shifts/migrations/0076_shifttemplate_end_date.py
index f0bee3db1..c4d80047b 100644
--- a/tapir/shifts/migrations/0075_shifttemplate_end_date.py
+++ b/tapir/shifts/migrations/0076_shifttemplate_end_date.py
@@ -1,4 +1,4 @@
-# Generated by Django 5.2.13 on 2026-04-17 16:42
+# Generated by Django 5.2.15 on 2026-06-14 17:37
from django.db import migrations, models
@@ -6,7 +6,7 @@
class Migration(migrations.Migration):
dependencies = [
- ("shifts", "0074_alter_shift_num_required_attendances"),
+ ("shifts", "0075_shiftwatch_watched_capabilities"),
]
operations = [
From 61aeb933b7398427fce1b349488f8a1f1f9854fa Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Fri, 10 Jul 2026 17:05:01 +0200
Subject: [PATCH 10/14] transl
---
.../shifts/templates/shifts/shift_detail.html | 15 +-
.../locale/de/LC_MESSAGES/django.po | 191 +++++++++++-------
2 files changed, 123 insertions(+), 83 deletions(-)
diff --git a/tapir/shifts/templates/shifts/shift_detail.html b/tapir/shifts/templates/shifts/shift_detail.html
index bb674f208..2c0fd8ca8 100644
--- a/tapir/shifts/templates/shifts/shift_detail.html
+++ b/tapir/shifts/templates/shifts/shift_detail.html
@@ -234,12 +234,17 @@ #{{ forloop.counter }}
{% elif not slot.is_occupied %}
{% blocktranslate asvar self_register_tooltip %}You can only register
yourself
- for a shift if:
- -You are not registered to another slot in that shift
+ for a shift if:
+
+ -You are not registered to another slot in that shift
+
-You have the required qualification (if you want to get a
- qualification, contact the member office)
- -The shift is in the future
- -The shift is not cancelled (holidays...)
+ qualification, contact the member office)
+
+ -The shift is in the future
+
+ -The shift is not cancelled (holidays...)
+
{% endblocktranslate %}
{% autoescape off %}
diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po
index 0e17400fd..e33261ffd 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-10 17:03+0200\n"
"PO-Revision-Date: 2025-07-07 13:06+0000\n"
"Last-Translator: Weblate Admin \n"
"Language-Team: German \n"
@@ -343,7 +343,7 @@ msgstr "Benutzername bearbeiten"
#: core/templates/core/featureflag_list.html:30
#: shifts/templates/shifts/shift_detail.html:65
#: shifts/templates/shifts/shift_template_detail.html:29
-#: shifts/templates/shifts/shift_template_detail.html:117
+#: shifts/templates/shifts/shift_template_detail.html:122
#: shifts/templates/shifts/user_shifts_overview_tag.html:14
msgid "Edit"
msgstr "Bearbeiten"
@@ -652,7 +652,7 @@ msgstr "Wird normalerweise leer gelassen. Das Datum kann in der Zukunft liegen,
msgid "Number of shares to create"
msgstr "Anzahl zu erstellender Anteile"
-#: coop/forms.py:67
+#: coop/forms.py:67 shifts/forms.py:478
msgid "The end date must be later than the start date."
msgstr "Das Enddatum muss später als das Start-Datum sein"
@@ -1113,7 +1113,7 @@ msgstr "Bewerber*in erzeugen"
#: shifts/templates/shifts/register_user_to_shift_slot.html:27
#: shifts/templates/shifts/register_user_to_shift_slot_template.html:26
#: shifts/templates/shifts/shift_detail.html:249
-#: shifts/templates/shifts/shift_template_detail.html:88
+#: shifts/templates/shifts/shift_template_detail.html:93
msgid "Register"
msgstr "Anmelden"
@@ -2089,6 +2089,7 @@ msgid "Submit"
msgstr "Abschicken"
#: coop/templates/coop/extra_share_request.html:92
+#: shifts/templates/shifts/shift_template_set_end_date.html:25
#: shifts/templates/shifts/user_shifts_overview_tag.html:177
msgid "Cancel"
msgstr "Abmelden"
@@ -2275,7 +2276,7 @@ msgstr ""
" "
#: coop/templates/coop/membershipresignation_detail.html:61
-#: shifts/models.py:535
+#: shifts/models.py:541
msgid "Cancellation reason"
msgstr "Grund der Kündigung"
@@ -2522,7 +2523,7 @@ msgstr ""
" "
#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:56
-#: shifts/models.py:933 shifts/templates/shifts/shift_day_printable.html:214
+#: shifts/models.py:939 shifts/templates/shifts/shift_day_printable.html:214
#: shifts/templates/shifts/shift_day_printable.html:276
#: shifts/templates/shifts/shift_detail.html:304
#: shifts/templates/shifts/shift_detail_printable.html:51
@@ -2530,7 +2531,7 @@ msgid "Attended"
msgstr "Teilgenommen"
#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:58
-#: shifts/models.py:932
+#: shifts/models.py:938
msgid "Pending"
msgstr "Ausstehend"
@@ -2703,7 +2704,7 @@ msgstr "Hat Qualifikation"
msgid "Does not have qualification"
msgstr "Hat die Qualifikation nicht"
-#: coop/views/shareowner.py:656 shifts/forms.py:788
+#: coop/views/shareowner.py:656 shifts/forms.py:809
msgid "ABCD Week"
msgstr "ABCD-Woche"
@@ -2836,8 +2837,8 @@ 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
+#: core/templates/core/email_list.html:39 shifts/models.py:508
+#: shifts/models.py:1077 shifts/templates/shifts/user_shift_account_log.html:29
msgid "Description"
msgstr "Beschreibung"
@@ -3190,86 +3191,86 @@ msgstr "Das ausgewählte Mitglied muss ein investierendes Mitglied sein."
msgid "This member is registered to at least one ABCD shift. Please confirm the change of attendance mode with the checkbox below."
msgstr ""
-#: shifts/forms.py:496
+#: shifts/forms.py:462 shifts/forms.py:628
+msgid "Cancellation Reason"
+msgstr "Grund der Absage"
+
+#: shifts/forms.py:517
msgid "I have read the warning about the cancelled attendances and confirm that the exemption should be created"
msgstr "Ich habe die Warnung über die abgesagte Schicht-Anwesenheit gelesen und bestätige, dass die Befreiung erzeugt werden soll"
-#: shifts/forms.py:503
+#: shifts/forms.py:524
msgid "I have read the warning about the cancelled ABCD attendances and confirm that the exemption should be created"
msgstr "Ich habe die Warnung über die abgebrochene ABCD-Teilnahme gelesen und bestätige, dass die Befreiung erzeugt werden soll"
-#: shifts/forms.py:561
+#: shifts/forms.py:582
#, python-format
msgid "The user will be unregistered from the following ABCD shifts because the exemption is longer than %(number_of_cycles)s cycles: %(attendances_display)s "
msgstr "Das Mitglied wird von den folgenden ABCD-Schichten abgemeldet, weil die Befreiung länger als %(number_of_cycles)s Schichtzyklen ist: %(attendances_display)s "
-#: shifts/forms.py:582
+#: shifts/forms.py:603
msgid "This shift has been deleted. It is not possible to cancel it."
msgstr "Diese Schicht wurde bereits gelöscht. Es ist nicht möglich diese abzusagen."
-#: shifts/forms.py:593 shifts/templates/shifts/shift_detail.html:8
+#: shifts/forms.py:614 shifts/templates/shifts/shift_detail.html:8
#: shifts/templates/shifts/shift_detail.html:30
msgid "Shift"
msgstr "Schicht"
-#: shifts/forms.py:594
+#: shifts/forms.py:615
msgid "already cancelled"
msgstr "bereits bgesagt"
-#: shifts/forms.py:607
-msgid "Cancellation Reason"
-msgstr "Grund der Absage"
-
-#: shifts/forms.py:608
+#: shifts/forms.py:629
msgid "This reason will be applied to all cancelled shifts."
msgstr ""
-#: shifts/forms.py:636
+#: shifts/forms.py:657
msgid "I understand that updating this ABCD shift will update all the corresponding future shifts"
msgstr ""
-#: shifts/forms.py:655
+#: shifts/forms.py:676
msgid "ABCD-Week"
msgstr "ABCD-Woche"
-#: shifts/forms.py:659
+#: shifts/forms.py:680
msgid "Weekdays"
msgstr "Wochentage"
-#: shifts/forms.py:684
+#: shifts/forms.py:705
msgid "I understand that adding or editing a slot to this ABCD shift will affect all the corresponding future shifts"
msgstr ""
-#: shifts/forms.py:693
+#: shifts/forms.py:714
msgid "I understand that this will delete the shift exemption and create a membership pause"
msgstr ""
-#: shifts/forms.py:725 shifts/forms.py:793 shifts/views/views.py:419
-#: shifts/views/views.py:420
+#: shifts/forms.py:746 shifts/forms.py:814 shifts/views/views.py:463
+#: shifts/views/views.py:464
msgid "Shift changes you would like to be informed about"
msgstr "Schicht-Änderungen, bei denen du informiert werden möchtest"
-#: shifts/forms.py:732
+#: shifts/forms.py:753
msgid "Notify me when these capabilities become available or unavailable"
msgstr ""
-#: shifts/forms.py:736
+#: shifts/forms.py:757
msgid "Get notified when someone with specific skills registers or unregisters"
msgstr ""
-#: shifts/forms.py:782 shifts/templates/shifts/shift_template_detail.html:7
+#: shifts/forms.py:803 shifts/templates/shifts/shift_template_detail.html:7
#: shifts/templates/shifts/shift_template_detail.html:15
#: shifts/templates/shifts/user_shifts_overview_tag.html:31
#: shifts/templates/shifts/user_shifts_overview_tag.html:43
msgid "ABCD Shift"
msgstr "ABCD-Schicht"
-#: shifts/forms.py:799
+#: shifts/forms.py:820
#, python-format
msgid "If weekdays or %(shift_template_group)s are selected, %(shift_templates)s may not be selected, and vice versa."
msgstr ""
-#: shifts/forms.py:803
+#: shifts/forms.py:824
#, python-format
msgid "At least one of the fields (%(shift_templates)s, weekdays, or %(shift_template_group)s) must be selected."
msgstr ""
@@ -3334,7 +3335,7 @@ msgstr "Mir ist klar, dass ich bei dieser Schicht möglicherweise schwere Gewich
msgid "I understand that I may need to work high, for example up a ladder. I do not suffer from fear of heights."
msgstr "Mir ist klar, dass ich möglicherweise in großer Höhe arbeiten muss, zum Beispiel auf einer Leiter. Ich leide nicht unter Höhenangst."
-#: shifts/models.py:166 shifts/models.py:496
+#: shifts/models.py:166 shifts/models.py:502
msgid "If there are less members registered to a shift than that number, it will be highlighted in the shift calendar. The number of required attendances can't be higher than the slots in the resp. shift."
msgstr "Wenn weniger Mitlieder als diese Nummer zur Schicht registriert sind, wird diese blau angezeigt. Die Anzahl der benltigten Mitglieder kann nicht höher sein als die Anzahl vorhandener Slots."
@@ -3342,47 +3343,51 @@ msgstr "Wenn weniger Mitlieder als diese Nummer zur Schicht registriert sind, wi
msgid "This determines from which date shifts should be generated from this ABCD shift."
msgstr ""
-#: shifts/models.py:181 shifts/models.py:510
+#: shifts/models.py:183
+msgid "All shifts after this date will be cancelled."
+msgstr ""
+
+#: shifts/models.py:186 shifts/models.py:516
#: shifts/templates/shifts/shift_block_tag.html:10
msgid "Flexible time"
msgstr "Zeit flexibel"
-#: shifts/models.py:183 shifts/models.py:512
+#: shifts/models.py:188 shifts/models.py:518
msgid "If enabled, members who register for that shift can choose themselves the time where they come do their shift."
msgstr ""
-#: shifts/models.py:408 shifts/models.py:824
+#: shifts/models.py:414 shifts/models.py:830
#: shifts/templates/shifts/shift_detail.html:118
-#: shifts/templates/shifts/shift_template_detail.html:46
+#: shifts/templates/shifts/shift_template_detail.html:51
msgid "Chosen time"
msgstr "Ausgewählte Uhrzeit"
-#: shifts/models.py:410
+#: shifts/models.py:416
msgid "This shift lets you choose at what time you come during the day of the shift. In order to help organising the attendance, please specify when you expect to come.Setting or updating this field will set the time for all individual shifts generated from this ABCD shift.You can update the time of a single shift individually and at any time on the shift page."
msgstr ""
-#: shifts/models.py:494
+#: shifts/models.py:500
msgid "Number of required attendances"
msgstr "Anzahl notwendiger Teilnehmender"
-#: shifts/models.py:503
+#: shifts/models.py:509
msgid "Is shown on the shift page below the title"
msgstr ""
-#: shifts/models.py:523 shifts/models.py:529
+#: shifts/models.py:529 shifts/models.py:535
msgid "If 'flexible time' is enabled, then the time component is ignored"
msgstr ""
-#: shifts/models.py:826
+#: shifts/models.py:832
msgid "This shift lets you choose at what time you come during the day of the shift. In order to help organising the attendance, please specify when you expect to come."
msgstr "Diese Schicht ermöglicht dir auszusuchen, wann du kommen magst. Um die Planung zu erleichtern, gib bitte deine erwartete Ankunftszeit an."
-#: shifts/models.py:934 shifts/templates/shifts/shift_detail.html:314
+#: shifts/models.py:940 shifts/templates/shifts/shift_detail.html:314
#: shifts/templates/shifts/shift_detail_printable.html:52
msgid "Missed"
msgstr "Nicht erschienen"
-#: shifts/models.py:935 shifts/templates/shifts/shift_day_printable.html:216
+#: shifts/models.py:941 shifts/templates/shifts/shift_day_printable.html:216
#: shifts/templates/shifts/shift_day_printable.html:281
#: shifts/templates/shifts/shift_day_printable.html:283
#: shifts/templates/shifts/shift_detail.html:344
@@ -3390,58 +3395,58 @@ msgstr "Nicht erschienen"
msgid "Excused"
msgstr "Entschuldigt"
-#: shifts/models.py:936 shifts/templates/shifts/shift_detail.html:352
+#: shifts/models.py:942 shifts/templates/shifts/shift_detail.html:352
msgid "Cancelled"
msgstr "Abgesagt"
-#: shifts/models.py:937 shifts/templates/shifts/shift_day_printable.html:264
+#: shifts/models.py:943 shifts/templates/shifts/shift_day_printable.html:264
#: shifts/templates/shifts/shift_detail.html:336
#: shifts/templates/shifts/shift_detail_printable.html:94
#: shifts/templates/shifts/shift_filters.html:83
msgid "Looking for a stand-in"
msgstr "Sucht Vertretung"
-#: shifts/models.py:970
+#: shifts/models.py:976
msgid "🏠 ABCD"
msgstr "🏠 ABCD"
-#: shifts/models.py:971
+#: shifts/models.py:977
msgid "✈ Flying"
msgstr "✈ Fliegend"
-#: shifts/models.py:972
+#: shifts/models.py:978
msgid "❄ Frozen"
msgstr "❄ Eingefroren"
-#: shifts/models.py:1003
+#: shifts/models.py:1009
msgid "Is frozen"
msgstr "Ist eingefroren"
-#: shifts/models.py:1177
+#: shifts/models.py:1183
msgid "Cycle start date"
msgstr "Anfangsdatum"
-#: shifts/models.py:1198
+#: shifts/models.py:1204
msgid "Shift is almost full, only one spot left."
msgstr "Die Schicht ist fast voll, es ist nur noch ein Platz übrig."
-#: shifts/models.py:1199
+#: shifts/models.py:1205
msgid "Shift is full now."
msgstr "Die Schicht ist jetzt voll."
-#: shifts/models.py:1200
+#: shifts/models.py:1206
msgid "The Shift is understaffed!"
msgstr "Die Schicht ist jetzt unterbesetzt."
-#: shifts/models.py:1201
+#: shifts/models.py:1207
msgid "Shift stable: not understaffed, not fully staffed."
msgstr "Entwarnung. Die schicht ist nicht länger unterbesetzt, aber es noch Platz übrig"
-#: shifts/models.py:1203
+#: shifts/models.py:1209
msgid "One new attendance or more registered, but the shift is neither understaffed nor full or almost full."
msgstr "Ein Mitglied oder mehr hat sich registriert, aber die Schicht ist weder unterbesetzt noch (fast) voll"
-#: shifts/models.py:1206
+#: shifts/models.py:1212
msgid "One attendance or more un-registered, but the shift is neither understaffed nor full or almost full."
msgstr "Ein Mitglied oder mehr hat sich abgemeldet, aber die Schicht ist weder unterbesetzt noch (fast) voll"
@@ -4306,7 +4311,7 @@ msgstr "Flexible Arbeitszeit nicht angegeben"
#: shifts/templates/shifts/shift_day_printable.html:259
#: shifts/templates/shifts/shift_detail.html:145
#: shifts/templates/shifts/shift_detail_printable.html:90
-#: shifts/templates/shifts/shift_template_detail.html:68
+#: shifts/templates/shifts/shift_template_detail.html:73
msgid "Shift partner: "
msgstr "Schicht-Partner: "
@@ -4370,12 +4375,12 @@ msgid "Number"
msgstr "Nummer"
#: shifts/templates/shifts/shift_detail.html:112
-#: shifts/templates/shifts/shift_template_detail.html:42
+#: shifts/templates/shifts/shift_template_detail.html:47
msgid "Details"
msgstr "Details"
#: shifts/templates/shifts/shift_detail.html:113
-#: shifts/templates/shifts/shift_template_detail.html:44
+#: shifts/templates/shifts/shift_template_detail.html:49
msgid "Registered user"
msgstr "Angemeldete*r Nutzer*in"
@@ -4388,7 +4393,7 @@ msgid "Do you meet the requirements?"
msgstr "Erfüllst du die Voraussetzungen?"
#: shifts/templates/shifts/shift_detail.html:121
-#: shifts/templates/shifts/shift_template_detail.html:49
+#: shifts/templates/shifts/shift_template_detail.html:54
msgid "Member-Office actions"
msgstr "Mitgliederbüro Aktionen"
@@ -4494,7 +4499,7 @@ msgstr ""
" "
#: shifts/templates/shifts/shift_detail.html:277
-#: shifts/templates/shifts/shift_template_detail.html:99
+#: shifts/templates/shifts/shift_template_detail.html:104
msgid "Not specified"
msgstr ""
@@ -4623,23 +4628,29 @@ msgstr ""
msgid "Duplicate"
msgstr "Dopplung"
-#: shifts/templates/shifts/shift_template_detail.html:38
+#: shifts/templates/shifts/shift_template_detail.html:34
+#, fuzzy
+#| msgid "Pay out end date"
+msgid "Set end date"
+msgstr "Auszahlungsende"
+
+#: shifts/templates/shifts/shift_template_detail.html:43
msgid "List of slots for this ABCD shifts"
msgstr "Liste des Slots für diese ABCD-Schicht"
-#: shifts/templates/shifts/shift_template_detail.html:43
+#: shifts/templates/shifts/shift_template_detail.html:48
msgid "Requirements"
msgstr ""
-#: shifts/templates/shifts/shift_template_detail.html:77
+#: shifts/templates/shifts/shift_template_detail.html:82
msgid "Unregister"
msgstr "Abmelden"
-#: shifts/templates/shifts/shift_template_detail.html:126
+#: shifts/templates/shifts/shift_template_detail.html:131
msgid "Future generated Shifts"
msgstr "Zukünftige erstellte Schichten"
-#: shifts/templates/shifts/shift_template_detail.html:136
+#: shifts/templates/shifts/shift_template_detail.html:141
msgid "Past generated Shifts"
msgstr "Vergangene Schichten"
@@ -4678,6 +4689,27 @@ msgstr ""
msgid "Calendar of ABCD shifts"
msgstr "Kalender der ABCD-Schichten"
+#: shifts/templates/shifts/shift_template_set_end_date.html:7
+#: shifts/templates/shifts/shift_template_set_end_date.html:11
+#, fuzzy
+#| msgid "Pay out end date"
+msgid "Set end date for"
+msgstr "Auszahlungsende"
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:17
+msgid "Warning"
+msgstr ""
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:18
+msgid "All shifts generated from this ABCD-shift after the selected date will be cancelled. Registered members will be notified."
+msgstr ""
+
+#: shifts/templates/shifts/shift_template_set_end_date.html:22
+#, fuzzy
+#| msgid "Set shift attendance to"
+msgid "Set end date and cancel shifts"
+msgstr "Ändere den Schichtstatus zu"
+
#: shifts/templates/shifts/shiftexemption_list.html:38
msgid "Create shift exemption"
msgstr "Schicht-Befreiung erzeugen"
@@ -4709,7 +4741,7 @@ msgid "Recurring Shift Watches"
msgstr "Wiederholende Schichtbeobachtungen"
#: shifts/templates/shifts/shiftwatch_overview.html:25
-#: shifts/views/views.py:464
+#: shifts/views/views.py:508
msgid "Create a rule for recurring Shift Watches"
msgstr "Erstelle eine Regel für sich wiederholende Schichtbeobachtungen"
@@ -5043,7 +5075,7 @@ msgid "No watched shifts"
msgstr "Keine beobachteten Schichten"
#: shifts/templatetags/shifts.py:69 shifts/templatetags/shifts.py:174
-#: shifts/views/views.py:150
+#: shifts/views/views.py:152
msgid "General"
msgstr "Allgemein"
@@ -5142,27 +5174,33 @@ msgstr "Es konnte keine vollendete Schicht gefunden werden, die als Solidarität
msgid "Solidarity Shift given. Account Balance debited with -1."
msgstr "Die Solidaritätsschicht wurde vergeben. Von deinem Kontostand wird nun eine Schicht abgezogen."
-#: shifts/views/views.py:130 shifts/views/views.py:135
+#: shifts/views/views.py:132 shifts/views/views.py:137
#, python-format
msgid "Edit user shift data: %(name)s"
msgstr "Bearbeite Nutzer*in-Schichtdaten: %(name)s"
-#: shifts/views/views.py:203
+#: shifts/views/views.py:205
#, python-format
msgid "Shift account: %(name)s"
msgstr "Schichtkonto-Protokoll für: %(name)s"
-#: shifts/views/views.py:209
+#: shifts/views/views.py:211
#, fuzzy, python-format
#| msgid "Create manual shift account entry for: %(link)s"
msgid "Create manual shift account entry for: %(link)s"
msgstr "Erzeuge Schicht-Kontoeintrag für: %(link)s"
-#: shifts/views/views.py:402
+#: shifts/views/views.py:370
+#, fuzzy
+#| msgid "Shift attendance cancelled"
+msgid "Shift template was successfully cancelled"
+msgstr "Schicht"
+
+#: shifts/views/views.py:446
msgid "Frozen statuses updated."
msgstr ""
-#: shifts/views/views.py:467
+#: shifts/views/views.py:511
#, python-format
msgid "Please select either %(shift_template_group)s and/or weekdays, or alternatively %(shift_templates)s."
msgstr ""
@@ -6625,9 +6663,6 @@ msgstr "%(name)s hat an dem Willkommenstreffen noch nicht teilgenommen. Stelle s
#~ " Das Mitgliederbüro\n"
#~ " "
-#~ msgid "Shift attendance cancelled"
-#~ msgstr "Schicht"
-
#~ msgid "Buy"
#~ msgstr "Kaufen"
From 0f3de75c360f18ecfdf75f3bd977fc51cf008b9f Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Fri, 10 Jul 2026 17:08:08 +0200
Subject: [PATCH 11/14] transl
---
.../locale/de/LC_MESSAGES/django.po | 35 +++++++++++--------
1 file changed, 20 insertions(+), 15 deletions(-)
diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po
index e33261ffd..1376e0b6c 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-10 17:03+0200\n"
+"POT-Creation-Date: 2026-07-10 17:08+0200\n"
"PO-Revision-Date: 2025-07-07 13:06+0000\n"
"Last-Translator: Weblate Admin \n"
"Language-Team: German \n"
@@ -1112,7 +1112,7 @@ msgstr "Bewerber*in erzeugen"
#: coop/templates/coop/draftuser_register_form.html:29
#: shifts/templates/shifts/register_user_to_shift_slot.html:27
#: shifts/templates/shifts/register_user_to_shift_slot_template.html:26
-#: shifts/templates/shifts/shift_detail.html:249
+#: shifts/templates/shifts/shift_detail.html:254
#: shifts/templates/shifts/shift_template_detail.html:93
msgid "Register"
msgstr "Anmelden"
@@ -2525,7 +2525,7 @@ msgstr ""
#: coop/templates/coop/tags/user_coop_share_ownership_list_tag.html:56
#: shifts/models.py:939 shifts/templates/shifts/shift_day_printable.html:214
#: shifts/templates/shifts/shift_day_printable.html:276
-#: shifts/templates/shifts/shift_detail.html:304
+#: shifts/templates/shifts/shift_detail.html:309
#: shifts/templates/shifts/shift_detail_printable.html:51
msgid "Attended"
msgstr "Teilgenommen"
@@ -3382,7 +3382,7 @@ msgstr ""
msgid "This shift lets you choose at what time you come during the day of the shift. In order to help organising the attendance, please specify when you expect to come."
msgstr "Diese Schicht ermöglicht dir auszusuchen, wann du kommen magst. Um die Planung zu erleichtern, gib bitte deine erwartete Ankunftszeit an."
-#: shifts/models.py:940 shifts/templates/shifts/shift_detail.html:314
+#: shifts/models.py:940 shifts/templates/shifts/shift_detail.html:319
#: shifts/templates/shifts/shift_detail_printable.html:52
msgid "Missed"
msgstr "Nicht erschienen"
@@ -3390,17 +3390,17 @@ msgstr "Nicht erschienen"
#: shifts/models.py:941 shifts/templates/shifts/shift_day_printable.html:216
#: shifts/templates/shifts/shift_day_printable.html:281
#: shifts/templates/shifts/shift_day_printable.html:283
-#: shifts/templates/shifts/shift_detail.html:344
+#: shifts/templates/shifts/shift_detail.html:349
#: shifts/templates/shifts/shift_detail_printable.html:53
msgid "Excused"
msgstr "Entschuldigt"
-#: shifts/models.py:942 shifts/templates/shifts/shift_detail.html:352
+#: shifts/models.py:942 shifts/templates/shifts/shift_detail.html:357
msgid "Cancelled"
msgstr "Abgesagt"
#: shifts/models.py:943 shifts/templates/shifts/shift_day_printable.html:264
-#: shifts/templates/shifts/shift_detail.html:336
+#: shifts/templates/shifts/shift_detail.html:341
#: shifts/templates/shifts/shift_detail_printable.html:94
#: shifts/templates/shifts/shift_filters.html:83
msgid "Looking for a stand-in"
@@ -4414,7 +4414,7 @@ msgid "Cancels the search for a stand-in. Use this if you want to attend the shi
msgstr "Beendet die Suche nach Vertretung. Benutze dies, wenn du die Schicht wahrnehmen möchtest."
#: shifts/templates/shifts/shift_detail.html:185
-#: shifts/templates/shifts/shift_detail.html:325
+#: shifts/templates/shifts/shift_detail.html:330
msgid "Cancel looking for a stand-in"
msgstr "Beende die Suche nach Vertretung"
@@ -4484,12 +4484,17 @@ msgstr "Melde mich ab"
msgid ""
"You can only register\n"
" yourself\n"
-" for a shift if:
\n"
-" -You are not registered to another slot in that shift
\n"
+" for a shift if:\n"
+"
\n"
+" -You are not registered to another slot in that shift\n"
+"
\n"
" -You have the required qualification (if you want to get a\n"
-" qualification, contact the member office)
\n"
-" -The shift is in the future
\n"
-" -The shift is not cancelled (holidays...)
\n"
+" qualification, contact the member office)\n"
+"
\n"
+" -The shift is in the future\n"
+"
\n"
+" -The shift is not cancelled (holidays...)\n"
+"
\n"
" "
msgstr ""
"Du kannst dich nur für eine Schicht anmelden, wenn\n"
@@ -4498,12 +4503,12 @@ msgstr ""
"- die Schicht in der Zukunft liegt\n"
" "
-#: shifts/templates/shifts/shift_detail.html:277
+#: shifts/templates/shifts/shift_detail.html:282
#: shifts/templates/shifts/shift_template_detail.html:104
msgid "Not specified"
msgstr ""
-#: shifts/templates/shifts/shift_detail.html:360
+#: shifts/templates/shifts/shift_detail.html:365
msgid "Edit slot"
msgstr "Slot bearbeiten"
From ced1e2dcd2e77c974fcef789f8cb44bf8c1001e5 Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Fri, 10 Jul 2026 17:50:21 +0200
Subject: [PATCH 12/14] remove comment
---
tapir/shifts/views/views.py | 1 -
tapir/translations/locale/de/LC_MESSAGES/django.po | 14 +++++++-------
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/tapir/shifts/views/views.py b/tapir/shifts/views/views.py
index 8a4eb5d8a..d40c1788a 100644
--- a/tapir/shifts/views/views.py
+++ b/tapir/shifts/views/views.py
@@ -334,7 +334,6 @@ def get_queryset(self):
class ShiftTemplateEndDateView(
LoginRequiredMixin,
PermissionRequiredMixin,
- # TapirFormMixin,
generic.UpdateView,
):
permission_required = PERMISSION_SHIFTS_MANAGE
diff --git a/tapir/translations/locale/de/LC_MESSAGES/django.po b/tapir/translations/locale/de/LC_MESSAGES/django.po
index 1376e0b6c..8fc2554fc 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-10 17:08+0200\n"
+"POT-Creation-Date: 2026-07-10 17:50+0200\n"
"PO-Revision-Date: 2025-07-07 13:06+0000\n"
"Last-Translator: Weblate Admin \n"
"Language-Team: German \n"
@@ -3245,8 +3245,8 @@ msgstr ""
msgid "I understand that this will delete the shift exemption and create a membership pause"
msgstr ""
-#: shifts/forms.py:746 shifts/forms.py:814 shifts/views/views.py:463
-#: shifts/views/views.py:464
+#: shifts/forms.py:746 shifts/forms.py:814 shifts/views/views.py:462
+#: shifts/views/views.py:463
msgid "Shift changes you would like to be informed about"
msgstr "Schicht-Änderungen, bei denen du informiert werden möchtest"
@@ -4746,7 +4746,7 @@ msgid "Recurring Shift Watches"
msgstr "Wiederholende Schichtbeobachtungen"
#: shifts/templates/shifts/shiftwatch_overview.html:25
-#: shifts/views/views.py:508
+#: shifts/views/views.py:507
msgid "Create a rule for recurring Shift Watches"
msgstr "Erstelle eine Regel für sich wiederholende Schichtbeobachtungen"
@@ -5195,17 +5195,17 @@ msgstr "Schichtkonto-Protokoll für: %(name)s"
msgid "Create manual shift account entry for: %(link)s"
msgstr "Erzeuge Schicht-Kontoeintrag für: %(link)s"
-#: shifts/views/views.py:370
+#: shifts/views/views.py:369
#, fuzzy
#| msgid "Shift attendance cancelled"
msgid "Shift template was successfully cancelled"
msgstr "Schicht"
-#: shifts/views/views.py:446
+#: shifts/views/views.py:445
msgid "Frozen statuses updated."
msgstr ""
-#: shifts/views/views.py:511
+#: shifts/views/views.py:510
#, python-format
msgid "Please select either %(shift_template_group)s and/or weekdays, or alternatively %(shift_templates)s."
msgstr ""
From 4e4083f50fd6b5da69a326547c4274a825ec4adb Mon Sep 17 00:00:00 2001
From: crosspolar <18083323+crosspolar@users.noreply.github.com>
Date: Fri, 10 Jul 2026 18:10:33 +0200
Subject: [PATCH 13/14] remove cancel button
---
.../shifts/shift_template_set_end_date.html | 14 +++++++-------
tapir/translations/locale/de/LC_MESSAGES/django.po | 5 ++---
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/tapir/shifts/templates/shifts/shift_template_set_end_date.html b/tapir/shifts/templates/shifts/shift_template_set_end_date.html
index 938bb683b..2d0e14072 100644
--- a/tapir/shifts/templates/shifts/shift_template_set_end_date.html
+++ b/tapir/shifts/templates/shifts/shift_template_set_end_date.html
@@ -13,16 +13,16 @@