members/admin: group overview excel (#118)

closes #110

Reviewed-on: #118
Reviewed-by: Christian Merten <christian@merten.dev>
Co-authored-by: marius.klein <marius.klein@alpenverein-heidelberg.de>
Co-committed-by: marius.klein <marius.klein@alpenverein-heidelberg.de>
pull/119/head^2
marius.klein 11 months ago committed by Christian Merten
parent 530aea3244
commit d1a8e7f159

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\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"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -268,6 +268,10 @@ msgstr "Hinweise für Jugendleiter*innen erstellen"
msgid "Finance overview"
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
msgid "Invite as user"
msgstr "Als Kompassbenutzer*in einladen"

@ -20,6 +20,7 @@ from django import forms
from django.contrib import admin, messages
from django.contrib.admin import DateFieldListFilter
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.translation import gettext_lazy as _
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.core.exceptions import PermissionDenied, ValidationError
from .pdf import render_tex, fill_pdf_form, merge_pdfs, serve_pdf
from .excel import generate_group_overview
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 utils import get_member, RestrictedFileField
from schwifty import IBAN
from .pdf import media_path, media_dir
#from easy_select2 import apply_select2
@ -791,6 +794,7 @@ class GroupAdminForm(forms.ModelForm):
self.fields['leiters'].queryset = Member.objects.filter(group__name='Jugendleiter')
class GroupAdmin(CommonAdminMixin, admin.ModelAdmin):
fields = ['name', 'description', 'year_from', 'year_to', 'leiters', 'contact_email', 'show_website',
'weekday', ('start_time', 'end_time')]
@ -799,6 +803,38 @@ class GroupAdmin(CommonAdminMixin, admin.ModelAdmin):
inlines = [RegistrationPasswordInline, PermissionOnGroupInline]
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):
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