Add a team attendance KPI panel and no-show check-in tracking
Team pages now show, for the selected season: overall attendance rate, best/worst attenders, players who missed the last 2 practices, and no-shows (an affirmative RSVP checked in as absent). No-shows need a real distinction the RSVP status alone can't make, so Attendance gains a separate showed_up tri-state field, usable today via Django admin -- a full check-in screen is future work for the coaches app. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R1gj3J1QPfP38XWpnpbFpy
This commit is contained in:
@@ -17,6 +17,7 @@ from controlpanel.messages import notify
|
||||
from controlpanel.mixins import RedirectOnInvalidMixin
|
||||
from controlpanel.services.statistics import club_attention, club_charts, club_statistics
|
||||
from events.models import Event, EventSeries, Location, Opponent
|
||||
from events.services.attendance import player_attendance_rankings, players_who_missed_recent_practices, team_attendance_rate, team_no_shows
|
||||
from formbuilder.models import Form as FormBuilderForm
|
||||
from formbuilder.models import Submission
|
||||
from members.models import Family, FamilyMembership, Member
|
||||
@@ -757,6 +758,10 @@ class TeamDetailView(ClubStaffRequiredMixin, DetailView):
|
||||
|
||||
roster = TeamMembership.objects.none()
|
||||
staff = StaffAssignment.objects.none()
|
||||
attendance_rate = None
|
||||
top_attenders, bottom_attenders = [], []
|
||||
missed_practices = Member.objects.none()
|
||||
no_shows = []
|
||||
if season is not None:
|
||||
roster = list(TeamMembership.objects.filter(team=team, season=season).select_related("member", "position").order_by("position__ordering", "member__last_name"))
|
||||
staff = list(StaffAssignment.objects.filter(team=team, season=season).select_related("member", "position").order_by("position__ordering", "member__last_name"))
|
||||
@@ -766,6 +771,13 @@ class TeamDetailView(ClubStaffRequiredMixin, DetailView):
|
||||
for assignment in staff:
|
||||
assignment.edit_form = StaffAssignmentForm(instance=assignment, club=club, team=team, season=season)
|
||||
|
||||
attendance_rate = team_attendance_rate(team, season)
|
||||
rankings = player_attendance_rankings(team, season)
|
||||
top_attenders = rankings[:5]
|
||||
bottom_attenders = list(reversed(rankings))[:5]
|
||||
missed_practices = players_who_missed_recent_practices(team, season)
|
||||
no_shows = team_no_shows(team, season)[:10]
|
||||
|
||||
return super().get_context_data(
|
||||
seasons=Season.objects.filter(club=club).order_by("-start_date"),
|
||||
selected_season=season,
|
||||
@@ -774,6 +786,11 @@ class TeamDetailView(ClubStaffRequiredMixin, DetailView):
|
||||
can_manage=can_manage,
|
||||
roster_form=TeamMembershipForm(club=club, team=team, season=season) if can_manage and season else None,
|
||||
staff_form=StaffAssignmentForm(club=club, team=team, season=season) if can_manage and season else None,
|
||||
attendance_rate=attendance_rate,
|
||||
top_attenders=top_attenders,
|
||||
bottom_attenders=bottom_attenders,
|
||||
missed_practices=missed_practices,
|
||||
no_shows=no_shows,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user