Gruppenübersicht erstellen #118

Merged
christian.merten merged 10 commits from MK/group_overview into main 11 months ago

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-01 21:48+0100\n" "POT-Creation-Date: 2025-02-01 14:54+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -268,6 +268,10 @@ msgstr "Hinweise für Jugendleiter*innen erstellen"
msgid "Finance overview" msgid "Finance overview"
msgstr "Kostenübersicht" msgstr "Kostenübersicht"
#: templates/admin/members/group/change_list.html
msgid "Generate group overview"
msgstr "Gruppenübersicht erstellen"
#: templates/admin/members/member/change_form_object_tools.html #: templates/admin/members/member/change_form_object_tools.html
msgid "Invite as user" msgid "Invite as user"
msgstr "Als Kompassbenutzer*in einladen" msgstr "Als Kompassbenutzer*in einladen"

@ -20,6 +20,7 @@ from django import forms
from django.contrib import admin, messages from django.contrib import admin, messages
from django.contrib.admin import DateFieldListFilter from django.contrib.admin import DateFieldListFilter
from django.contrib.contenttypes.admin import GenericTabularInline from django.contrib.contenttypes.admin import GenericTabularInline
from contrib.media import serve_media, ensure_media_dir
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.db.models import TextField, ManyToManyField, ForeignKey, Count,\ from django.db.models import TextField, ManyToManyField, ForeignKey, Count,\
@ -28,6 +29,7 @@ from django.forms import Textarea, RadioSelect, TypedChoiceField, CheckboxInput
from django.shortcuts import render from django.shortcuts import render
from django.core.exceptions import PermissionDenied, ValidationError from django.core.exceptions import PermissionDenied, ValidationError
from .pdf import render_tex, fill_pdf_form, merge_pdfs, serve_pdf from .pdf import render_tex, fill_pdf_form, merge_pdfs, serve_pdf
from .excel import generate_group_overview
from contrib.admin import CommonAdminInlineMixin, CommonAdminMixin from contrib.admin import CommonAdminInlineMixin, CommonAdminMixin
@ -44,6 +46,7 @@ from mailer.mailutils import send as send_mail, get_echo_link
from django.conf import settings from django.conf import settings
from utils import get_member, RestrictedFileField from utils import get_member, RestrictedFileField
from schwifty import IBAN from schwifty import IBAN
from .pdf import media_path, media_dir
#from easy_select2 import apply_select2 #from easy_select2 import apply_select2
@ -791,6 +794,7 @@ class GroupAdminForm(forms.ModelForm):
self.fields['leiters'].queryset = Member.objects.filter(group__name='Jugendleiter') self.fields['leiters'].queryset = Member.objects.filter(group__name='Jugendleiter')
class GroupAdmin(CommonAdminMixin, admin.ModelAdmin): class GroupAdmin(CommonAdminMixin, admin.ModelAdmin):
fields = ['name', 'description', 'year_from', 'year_to', 'leiters', 'contact_email', 'show_website', fields = ['name', 'description', 'year_from', 'year_to', 'leiters', 'contact_email', 'show_website',
'weekday', ('start_time', 'end_time')] 'weekday', ('start_time', 'end_time')]
@ -799,6 +803,38 @@ class GroupAdmin(CommonAdminMixin, admin.ModelAdmin):
inlines = [RegistrationPasswordInline, PermissionOnGroupInline] inlines = [RegistrationPasswordInline, PermissionOnGroupInline]
search_fields = ('name',) search_fields = ('name',)
def get_urls(self):
urls = super().get_urls()
def wrap(view):
def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
wrapper.model_admin = self
return update_wrapper(wrapper, view)
custom_urls = [
path('action/', self.action_view, name='members_group_action'),
]
return custom_urls + urls
def action_view(self, request):
if "group_overview" in request.POST:
return self.group_overview(request)
def group_overview(self, request):
if not request.user.has_perm('members.view_group'):
messages.error(request,
_("You are not allowed to create a group overview."))
return HttpResponseRedirect(reverse('admin:%s_%s_changelist' % (self.opts.app_label, self.opts.model_name)))
ensure_media_dir()
filename = generate_group_overview(all_groups=self.model.objects.all())
response = serve_media(filename=filename, content_type='application/xlsx')
return response
class ActivityCategoryAdmin(admin.ModelAdmin): class ActivityCategoryAdmin(admin.ModelAdmin):
fields = ['name', 'description'] fields = ['name', 'description']

@ -0,0 +1,69 @@
from datetime import datetime
import os
import xlsxwriter
from django.conf import settings
from contrib.media import media_path
from .models import WEEKDAYS
def generate_group_overview(all_groups, limit_to_public = True):
"""
Creates an Excel Sheet with an overview of all the groups, their dates, times, age range and
number of members, etc.
arguments:
limit_to_public (optional, default is True): If False, all groups are returned in the overview,
including technical ones. If True, only groups with the flag "show_on_website" are returned.
"""
today = f"{datetime.today():%d.%m.%Y}"
filename = f"gruppenuebersicht_jdav_{settings.SEKTION}_{today}.xlsx"
workbook = xlsxwriter.Workbook(media_path(filename))
default = workbook.add_format({'text_wrap' : True, 'border': 1})
bold = workbook.add_format({'bold': True, 'border': 1})
title = workbook.add_format({'bold': True, 'font_size': 16, 'align': 'center'})
right = workbook.add_format({'bold': True, 'align': 'right'})
worksheet = workbook.add_worksheet()
worksheet.merge_range(0, 0, 0, 6, f"Gruppenübersicht JDAV {settings.SEKTION}", title)
row = 1
worksheet.write(row, 0, "Gruppe", bold)
worksheet.write(row, 1, "Wochentag", bold)
worksheet.write(row, 2, "Uhrzeit", bold)
worksheet.write(row, 3, "Altersgruppe", bold)
worksheet.write(row, 4, "TN", bold)
worksheet.write(row, 5, "JL", bold)
worksheet.write(row, 6, "Jugendleiter*innen", bold)
for group in all_groups:
# choose if only official youth groups on the website are shown
if limit_to_public and not group.show_website:
continue
row = row + 1
wd = f"{WEEKDAYS[group.weekday][1]}" if group.weekday else 'kein Wochentag'
times = f"{group.start_time:%H:%M} - {group.end_time:%H:%M}" if group.start_time and group.end_time else 'keine Zeiten'
yl_count = len([member for member in group.member_set.all() if member in group.leiters.all()])
tn_count = group.member_set.count() - yl_count
members = f"JG {group.year_from} - {group.year_to}"
leaders = f"{', '.join([yl.name for yl in group.leiters.all()])}"
worksheet.write(row, 0, group.name, default)
worksheet.write(row, 1, wd, default)
worksheet.write(row, 2, times, default)
worksheet.write(row, 3, members, default)
worksheet.write(row, 4, tn_count, default)
worksheet.write(row, 5, yl_count, default)
worksheet.write(row, 6, leaders, default)
worksheet.write(row+2, 6, f"Stand: {today}", right)
# set column width
worksheet.set_column_pixels(0, 0, 100)
worksheet.set_column_pixels(1, 1, 80)
worksheet.set_column_pixels(2, 2, 90)
worksheet.set_column_pixels(3, 3, 120)
worksheet.set_column_pixels(4, 4, 20)
worksheet.set_column_pixels(5, 5, 20)
worksheet.set_column_pixels(6, 6, 140)
workbook.close()
return filename

@ -0,0 +1,15 @@
{% extends "admin/change_list.html" %}
{% load i18n admin_urls %}
{% block object-tools-items %}
<li>
<form method="post" action="{% url 'admin:members_group_action' %}">
{% csrf_token %}
<input type="submit" name="group_overview" value="{% trans 'Generate group overview' %}">
</form>
</li>
{{block.super}}
{% endblock %}
Loading…
Cancel
Save