membershipworks: Add basic per-month event report
This commit is contained in:
parent
34821e1c58
commit
270e6c7837
29
membershipworks/dashboard.py
Normal file
29
membershipworks/dashboard.py
Normal 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")
|
@ -436,6 +436,14 @@ class EventExt(Event):
|
|||||||
max_digits=13, decimal_places=4, default=0
|
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:
|
class Meta:
|
||||||
verbose_name = "event"
|
verbose_name = "event"
|
||||||
|
|
||||||
|
@ -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 %}
|
0
membershipworks/templatetags/__init__.py
Normal file
0
membershipworks/templatetags/__init__.py
Normal file
12
membershipworks/templatetags/membershipworks_tags.py
Normal file
12
membershipworks/templatetags/membershipworks_tags.py
Normal 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
|
@ -1,6 +1,6 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from .views import MemberAutocomplete, upcoming_events
|
from .views import MemberAutocomplete, upcoming_events, EventReport
|
||||||
|
|
||||||
app_name = "membershipworks"
|
app_name = "membershipworks"
|
||||||
|
|
||||||
@ -15,4 +15,9 @@ urlpatterns = [
|
|||||||
upcoming_events,
|
upcoming_events,
|
||||||
name="upcoming-events",
|
name="upcoming-events",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"event-report/<int:year>/<int:month>/",
|
||||||
|
EventReport.as_view(month_format="%m"),
|
||||||
|
name="event-report",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
@ -3,12 +3,13 @@ from datetime import datetime
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
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.shortcuts import render
|
||||||
|
from django.views.generic.dates import MonthArchiveView
|
||||||
|
|
||||||
from dal import autocomplete
|
from dal import autocomplete
|
||||||
|
|
||||||
from .models import Member
|
from .models import Member, EventExt
|
||||||
from membershipworks import MembershipWorks
|
from membershipworks import MembershipWorks
|
||||||
|
|
||||||
|
|
||||||
@ -101,3 +102,10 @@ def upcoming_events(request):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
return render(request, "membershipworks/upcoming_events.dj.html", context)
|
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"
|
||||||
|
Loading…
Reference in New Issue
Block a user