membershipworks: Add basic per-month event report

This commit is contained in:
Adam Goldsmith 2024-01-15 21:31:06 -05:00
parent 34821e1c58
commit 270e6c7837
7 changed files with 131 additions and 3 deletions

View File

@ -0,0 +1,29 @@
from typing import Any
from datetime import datetime
from django.urls import reverse
import dashboard
@dashboard.register
class MembershipworksDashboardFragment(dashboard.DashboardFragment):
name = "MembershipWorks"
template = "dashboard/links_card.dj.html"
@property
def context(self) -> Any:
links = {}
if self.request.user.has_perm("membershipworks.view_event"):
now = datetime.now()
links["Event Report"] = reverse(
"membershipworks:event-report",
kwargs={"year": now.year, "month": now.month},
)
return {"links": links}
@property
def visible(self) -> bool:
return self.request.user.has_perm("doorcontrol.view_hidevent")

View File

@ -436,6 +436,14 @@ class EventExt(Event):
max_digits=13, decimal_places=4, default=0
)
# TODO: ideally this would be a generated column or annotation,
# but I couldn't get the types to work out
@property
def person_hours(self):
if self.duration is None:
return None
return self.count * self.duration
class Meta:
verbose_name = "event"

View File

@ -0,0 +1,66 @@
{% extends "base.dj.html" %}
{% load membershipworks_tags %}
{% block title %}Event Report{% endblock %}
{% block content %}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th for="column">Title</th>
<th for="column">Date</th>
<th for="column">Instructor</th>
<th for="column">Category</th>
<th for="column">Ticket Count</th>
<th for="column">Ticket Cap</th>
<th for="column">Meetings</th>
<th for="column">Total Duration</th>
<th for="column">Person Hours</th>
</tr>
</thead>
<tbody>
{% for event in object_list %}
<tr>
<td>
<a href="https://membershipworks.com/admin/#!event/admin/{{ event.url }}">{{ event.title }}</a>
</td>
<td>{{ event.start|date }}</td>
<td>{{ event.instructor }}</td>
<td>{{ event.category }}</td>
<td>{{ event.count }}</td>
<td>{{ event.cap }}</td>
<td>{{ event.meeting_times.count }}</td>
<td>{{ event.duration|duration_as_hours }}</td>
<td>{{ event.person_hours|duration_as_hours }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
{% if previous_month %}
<li class="page-item">
<a class="page-link"
href="{% url 'membershipworks:event-report' previous_month|date:"Y" previous_month|date:"m" %}">
<i class="bi bi-arrow-left"></i>
{{ previous_month|date:"F Y" }}
</a>
</li>
{% endif %}
<li class="page-item active">
<a class="page-link" href="#">{{ month|date:"F Y" }}</a>
</li>
{% if next_month %}
<li class="page-item">
<a class="page-link"
href="{% url 'membershipworks:event-report' next_month|date:"Y" next_month|date:"m" %}">
{{ next_month|date:"F Y" }}
<i class="bi bi-arrow-right"></i>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endblock %}

View File

View File

@ -0,0 +1,12 @@
from datetime import timedelta
from django import template
register = template.Library()
@register.filter
def duration_as_hours(td: timedelta) -> str | None:
if td is None:
return None
return td.total_seconds() / 60 / 60

View File

@ -1,6 +1,6 @@
from django.urls import path
from .views import MemberAutocomplete, upcoming_events
from .views import MemberAutocomplete, upcoming_events, EventReport
app_name = "membershipworks"
@ -15,4 +15,9 @@ urlpatterns = [
upcoming_events,
name="upcoming-events",
),
path(
"event-report/<int:year>/<int:month>/",
EventReport.as_view(month_format="%m"),
name="event-report",
),
]

View File

@ -3,12 +3,13 @@ from datetime import datetime
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.shortcuts import render
from django.views.generic.dates import MonthArchiveView
from dal import autocomplete
from .models import Member
from .models import Member, EventExt
from membershipworks import MembershipWorks
@ -101,3 +102,10 @@ def upcoming_events(request):
]
}
return render(request, "membershipworks/upcoming_events.dj.html", context)
class EventReport(PermissionRequiredMixin, MonthArchiveView):
permission_required = "membershipworks.view_eventext"
queryset = EventExt.objects.select_related("category", "instructor").all()
date_field = "start"
template_name = "membershipworks/event_report.dj.html"