feat(events): formal end date for recurring series

Add EventSeries.until: an explicit series end that caps occurrence
generation (whichever comes first — it, the generation horizon, or the
rule's own COUNT/UNTIL). Blank means open-ended. Surface it in the admin.
100% coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-12 19:22:48 +02:00
parent c535e5dc8c
commit 2653dd6d08
5 changed files with 45 additions and 3 deletions

View File

@@ -26,13 +26,13 @@ class AttendanceInline(admin.TabularInline):
@admin.register(EventSeries)
class EventSeriesAdmin(admin.ModelAdmin):
list_display = ["title", "kind", "rrule", "dtstart", "generated_until", "club"]
list_display = ["title", "kind", "rrule", "dtstart", "until", "generated_until", "club"]
list_filter = ["kind", "club"]
search_fields = ["title"]
autocomplete_fields = ["location", "opponent", "teams", "invited_members", "excluded_members"]
fieldsets = [
[None, {"fields": ["title", "kind"]}],
[_("Recurrence"), {"fields": ["rrule", "dtstart", "excluded_dates", "generated_until"]}],
[_("Recurrence"), {"fields": ["rrule", "dtstart", "until", "excluded_dates", "generated_until"]}],
[_("Timing"), {"fields": ["duration", "gathering_offset", "deadline_offset"]}],
[_("Audience"), {"fields": ["teams", "invited_members", "excluded_members"]}],
[_("Where"), {"fields": ["location", "opponent"]}],