membershipworks: Add new event attendee email report
All checks were successful
Ruff / ruff (push) Successful in 20s

This commit is contained in:
Adam Goldsmith 2024-02-02 19:26:06 -05:00
parent c3f51df7d4
commit 560225cdb3
6 changed files with 123 additions and 2 deletions

View File

@ -16,6 +16,7 @@ class MembershipworksDashboardFragment(dashboard.DashboardFragment):
if self.request.user.has_perm("membershipworks.view_event"): if self.request.user.has_perm("membershipworks.view_event"):
links["Event Report"] = reverse("membershipworks:event-index-report") links["Event Report"] = reverse("membershipworks:event-index-report")
links["Event Attendees"] = reverse("membershipworks:event-attendees")
return {"links": links} return {"links": links}

View File

@ -0,0 +1,26 @@
# Generated by Django 5.0.1 on 2024-02-02 22:07
from django.db import migrations
import django_db_views.migration_functions
import django_db_views.operations
class Migration(migrations.Migration):
dependencies = [
("membershipworks", "0012_eventattendeestats_eventtickettype"),
]
operations = [
django_db_views.operations.ViewRunPython(
code=django_db_views.migration_functions.ForwardViewMigration(
"SELECT eventext.event_ptr_id as event_id, tkt.uid, tkt.name, tkt.email, tkt.sum\n FROM\n membershipworks_eventext as eventext,\n JSON_TABLE(eventext.details, '$.usr[*]' COLUMNS (\n uid VARCHAR(24) PATH '$.uid',\n name VARCHAR(256) PATH '$.nam',\n email VARCHAR(256) PATH '$.eml',\n sum DOUBLE PATH '$.sum'\n )) as tkt",
"membershipworks_eventattendee",
engine="django.db.backends.mysql",
),
reverse_code=django_db_views.migration_functions.BackwardViewMigration(
"", "membershipworks_eventattendee", engine="django.db.backends.mysql"
),
atomic=False,
),
]

View File

@ -688,3 +688,28 @@ class EventAttendeeStats(DBView):
class Meta: class Meta:
managed = False managed = False
class EventAttendee(DBView):
event = models.ForeignKey(
EventExt, on_delete=models.CASCADE, related_name="attendees"
)
uid = models.ForeignKey(Member, on_delete=models.DO_NOTHING)
name = models.CharField(max_length=256)
email = models.CharField(max_length=256)
sum = models.FloatField()
view_definition = """
SELECT eventext.event_ptr_id as event_id, tkt.uid, tkt.name, tkt.email, tkt.sum
FROM
membershipworks_eventext as eventext,
JSON_TABLE(eventext.details, '$.usr[*]' COLUMNS (
uid VARCHAR(24) PATH '$.uid',
name VARCHAR(256) PATH '$.nam',
email VARCHAR(256) PATH '$.eml',
sum DOUBLE PATH '$.sum'
)) as tkt
"""
class Meta:
managed = False

View File

@ -0,0 +1,27 @@
{% extends "base.dj.html" %}
{% load render_table from django_tables2 %}
{% block title %}Event Attendees{% endblock %}
{% block admin_link %}
{% url 'admin:membershipworks_eventext_changelist' %}
{% endblock %}
{% block content %}
<form method="get" class="container-fluid">
<div class="row g-2 align-items-center">
<div class="col-auto">
<div class="form-floating">
<input type="date"
class="form-control"
id="newSince"
name="new_since"
value="{{ filter.form.new_since.value }}">
<label for="newSince">New Since</label>
</div>
</div>
<button class="btn btn-primary col-auto" type="submit">Filter</button>
<div class="col-auto">{% include "cmsmanage/components/download_table.dj.html" %}</div>
</div>
</form>
{% render_table table %}
{% endblock %}

View File

@ -1,6 +1,7 @@
from django.urls import path from django.urls import path
from .views import ( from .views import (
EventAttendeeListView,
EventIndexReport, EventIndexReport,
EventInvoiceView, EventInvoiceView,
EventMonthReport, EventMonthReport,
@ -42,4 +43,9 @@ urlpatterns = [
EventInvoiceView.as_view(), EventInvoiceView.as_view(),
name="event-invoice", name="event-invoice",
), ),
path(
"event-attendees",
EventAttendeeListView.as_view(),
name="event-attendees",
),
] ]

View File

@ -4,24 +4,27 @@ from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import Subquery
from django.db.models.functions import TruncMonth, TruncYear from django.db.models.functions import TruncMonth, TruncYear
from django.shortcuts import render from django.shortcuts import render
from django.template.defaultfilters import floatformat from django.template.defaultfilters import floatformat
from django.views.generic import DetailView from django.views.generic import DetailView, ListView
from django.views.generic.dates import ( from django.views.generic.dates import (
ArchiveIndexView, ArchiveIndexView,
MonthArchiveView, MonthArchiveView,
YearArchiveView, YearArchiveView,
) )
import django_filters
import django_tables2 as tables import django_tables2 as tables
from dal import autocomplete from dal import autocomplete
from django_filters.views import BaseFilterView
from django_tables2 import A, SingleTableMixin from django_tables2 import A, SingleTableMixin
from django_tables2.export.views import ExportMixin from django_tables2.export.views import ExportMixin
from membershipworks.membershipworks_api import MembershipWorks from membershipworks.membershipworks_api import MembershipWorks
from .models import EventExt, Member from .models import EventAttendee, EventExt, Member
class MemberAutocomplete(autocomplete.Select2QuerySetView): class MemberAutocomplete(autocomplete.Select2QuerySetView):
@ -329,3 +332,36 @@ class EventInvoiceView(SingleTableMixin, PermissionRequiredMixin, DetailView):
def get_table_kwargs(self): def get_table_kwargs(self):
return {"event": self.object} return {"event": self.object}
class EventAttendeeTable(tables.Table):
class Meta:
model = EventAttendee
fields = ("name", "email")
class EventAttendeeFilters(django_filters.FilterSet):
new_since = django_filters.DateFilter(
field_name="event__start", method="filter_new_since"
)
def filter_new_since(self, queryset, name, value):
return queryset.filter(**{f"{name}__gte": value}).exclude(
email__in=Subquery(
queryset.filter(**{f"{name}__lt": value}).values("email")
)
)
class EventAttendeeListView(
BaseFilterView, ExportMixin, SingleTableMixin, PermissionRequiredMixin, ListView
):
permission_required = "membershipworks.view_eventext"
queryset = EventAttendee.objects.all()
table_class = EventAttendeeTable
template_name = "membershipworks/eventattendee_list.dj.html"
export_formats = ("csv", "xlsx", "ods")
filterset_class = EventAttendeeFilters
def get_table_data(self):
return super().get_table_data().values("name", "email").distinct()