Skip to content

Add Session Points: opt-in attendance scoring per organization#83

Draft
danielhauser wants to merge 9 commits into
HaDiNet:masterfrom
danielhauser:feat/attendance-points
Draft

Add Session Points: opt-in attendance scoring per organization#83
danielhauser wants to merge 9 commits into
HaDiNet:masterfrom
danielhauser:feat/attendance-points

Conversation

@danielhauser

@danielhauser danielhauser commented Jun 24, 2026

Copy link
Copy Markdown

Overview

This PR adds an optional feature to shifts that allows organisations to track attendance and gives users the ability to excuse themselves. If a user neither attends nor formally excuses themselves, they receive a customisable, org-wide point penalty.

Motivation

At our organization (Belegungsausschuss), we currently rely on an awkward workaround to track attendance. Admins create two separate instances for every regular event: a positive one to signal attendance, and a negative one to act as an excuse. After the event, someone from the admin group has to manually verify attendance, track it in a separate Excel sheet, and calculate the difference between total events and the attended/excused users.

With this modification, we can completely get rid of these parallel structures and significantly reduce the administrative workload.

design

shift participants can now be in one of the following states:

  • Attended
  • Excused
  • No response

The no_response_penalty only applies when the shift was marked mandatory and the member didn't respond. I set it up org-wide we could also make that customizable per shift, but we don't need that in our work flow. I set the default 0.33 as this is what we are currently using. Excused members are neutral and we don't award points nor give them a penalty

For the actual point values I went with a resolution chain so orgs don't have to set things up on every single shift. For any shift the effective weight comes from shift.point_weight_override if it's set, otherwise from shift.shift_type.point_weight, and falls back to a default of 1 if neither is set. The same logic applies for the is_mandatory flag. So most shifts can just inherit from their type and an admin only has to override for special cases like a one-off training that should count double.

The whole feature is gated behind a single toggle per organisation. As long as that toggle stays off none of the new UI elements show up, the override fields don't appear on the shift form, and the summary view looks the same as today. So existing orgs won't notice any change.

for the graphical integration I just added a new table. Screenshot below
Screenshot 2026-06-24 at 14 26 29

and added new columns in the summary:
Screenshot 2026-06-24 at 14 34 32

some notes:

  • I left out a sperate "excuse another user" permission since I felt this is just artificial granularity. I couldn't come up with a reason why someone should be able to have permission to add user to a shift but not to excuse them. But still I would be happy to add an excuse_others_from_shifts permission if you'd prefer it.
  • we probably also need some sort of csv export, just to be able to archive attendance, that's going into a seperate mr

Adds two opt-in fields for the upcoming Session Points feature.
Defaults (False, 1.00) preserve current behaviour for every org.
excused_users lets a member declare they are not coming without being
counted as attending. point_weight_override and is_mandatory_override
are nullable and fall back to the shift type when blank, so one-off
events do not need a dedicated ShiftType.
attendance_points_enabled is the single boolean that gates the whole
feature per-organisation. no_response_penalty is the org-wide constant
deducted for unresponsive mandatory shifts.
Pure functions to resolve effective point weight and mandatory flag
for a shift, and to aggregate per-member attended/excused/missed
counts and the resulting saldo. Resolution falls back from a
per-shift override to the shift type to a default.
ShiftTypeForm gains is_mandatory and point_weight.
OrganizationShiftSummaryForm gains attendance_points_enabled and
no_response_penalty.
point_weight_override and is_mandatory_override are added to the
ShiftForm but popped at runtime when the bound organisation has
Session Points disabled. Orgs without the feature see no extra
fields on shift create/edit.
ExcuseSelfView adds the current user to Shift.excused_users and
cleans up any existing Participant. WithdrawExcuseView removes
them from the excused list. Both are gated by the existing
participate_in_shift permission, POST only, idempotent.
Adds an inclusion tag that resolves the effective point weight and
mandatory flag for a shift, and a small helper tag to check whether
the current request user is on the excused list. The shift detail
page shows the Session Points info line; the participants block
shows an Excuse or Withdraw button depending on the user's state.
All gated by attendance_points_enabled.
Extends member_shift_summary to compute per-member attended,
excused, missed and points using the scoring utility. The summary
template gains four columns rendered only when the organisation
has Session Points enabled, and sorts the table by points
descending in that case.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant