Commit Graph

7 Commits

Author SHA1 Message Date
744b623403 Separate guardians from members: a parent is not automatically a member
members/services/family.py enrolled a parent exactly like the child they were
registering, so every parent held a full membership: counted in the member
list, in the club and platform KPIs, and in the fee roll, with a fee record of
their own. ClubMembership.kind (member | guardian) separates the two.

A guardian is attached to the club only through their child. They hold the
login, can be contacted and can sit in a Group -- the stated exception -- but
they are not a member: no fee (clean() refuses one), absent from the member
list, the fee list and every member count, and not eligible for a roster or a
staff spot. A parent who also plays or coaches is a member who happens to be a
parent; the two facts are independent, which is why this is its own field
rather than inferred from FamilyMembership.role.

A field on ClubMembership rather than a separate model because everything that
answers "is this person attached to this club" already reads through that table
-- tenancy, groups, the club-wide event audience -- and a second kind of link
would need a parallel path through all of it. What changes is only who counts.

Two things that weren't obvious going in:

Excluding guardians had to be a subtraction, not a narrower filter. The obvious
move -- match only member-kind rows and drop the MEMBER-role branch, since an
active membership of any kind grants that role -- also hides someone the club
knows but hasn't signed up for a season yet, which is a real state the member
edit page supports. Two existing tests caught it. _guardians_only() subtracts
instead, so anyone who also plays, is on staff or runs the club stays visible.

Their tie to the club isn't seasonal but rides on a per-season row, so it has
to be carried forward or a parent silently drops off at the season boundary
while their child stays enrolled. Copied from the immediately preceding season
only, so a deliberate removal isn't resurrected from an older row.

The data migration reclassifies existing parents, deliberately skipping anyone
who plays, is on a team's staff or holds an elevated ClubRole -- demoting them
would strip them from their own team's roster eligibility. Anything ambiguous
stays a member, which an admin can flip; noticing someone quietly vanished is
much harder.

The import template gains a membership_kind column next to family_role (a
child marked guardian is refused), and the review screen shows what each row
will join as.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:11:41 +02:00
309bd4d83e Add referee assignment/eligibility system, team bulk-add, member Groups, and referee management dashboard with PDF export
Builds the referee workflow end to end: club-defined RefereeLevel/RefereeProfile
eligibility tied to teams, EventReferee assignment (member or external, with
fee/km payment tracking), an admin dashboard with KPI tiles, date-grouped game
tiles and range filters, and a downloadable payment form PDF modeled on the
club's existing paper document (using Club.legal_name when set). Also lands
team roster bulk-add, member mass-upload with family linking, and the
members.Group model, developed alongside this work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 21:39:19 +02:00
062da00bb9 Add the management app: club-facing UI + real fee-payment tracking
Gives clubs a self-service /manage/ area for members, families, teams,
roles, and season memberships, alongside real fee-payment tracking
(FeePayment, record_payment/mark_as_paid/remaining_balance) so a
membership's paid status reflects actual money received instead of a
single manually-set flag.
2026-08-03 17:01:15 +02:00
40255805c3 Modularize confirmation modal for destructive POST actions and add notify helper for concise message handling across the UI. 2026-07-16 18:34:03 +02:00
dd2e4b2169 feat: season-scope club memberships and convert to UniqueConstraint
ClubMembership is now tied to a Season (plus status / fee_status / sign-up
dates) and unique per (club, member, season). The CSV importer attaches
each membership to the club's current season (Season.get_current), skipping
the row with a clear error when none exists; the now-unreachable
"clubs created" bookkeeping is removed.

Register SeasonAdmin and rebuild ClubMembershipAdmin for the new fields, and
add an admin smoke test that asserts every model in authentication/club/
members/teams is registered and its changelist + add pages load.

Convert every unique_together to a Meta UniqueConstraint (Season,
ClubMembership, FamilyMembership) per Django's guidance. Regenerate
migrations. club, members, and importer stay at 100% coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 16:47:39 +02:00
638f85fa07 Remove redundant user re-link branch in CSV importer
update_or_create already persists member.user via defaults, so the
follow-up `if create_account and member.user_id is None` block was
unreachable dead code. Removing it brings importer coverage to 100%
with no behavior change (existing link-existing-user test still passes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 00:21:48 +02:00
f3b1ae7e82 Complete people-domain move into members app; keep names on Member
Finish relocating Member/Family/FamilyMembership from authentication into
a dedicated members app, and revert the half-applied move of member names
onto the global User.

- members: add first_name/last_name back to Member (the whole codebase —
  tests, CSV importer, club app, admin — assumes them, and login-less
  children in families need a name); restore local ordering/index and the
  member__last_name lookups in Family.__str__ and FamilyMembership.
- authentication: drop first_name/last_name from User; get_full_name/
  get_short_name delegate to the linked member, else fall back to email.
- migrations: create members.0001_initial, repoint club.ClubMembership FK
  (club.0005), delete the models from authentication (0004, rewritten to
  plain DeleteModel ops in child-first order to avoid a SQLite table-remake
  crash).
- fix stale imports across apps (authentication/club tests, CSV importer)
  and missing imports/URLs in members tests; add missing _ import in
  members/admin.py; export MemberCsvImporter from members.services.

Full suite green (64 tests), ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 00:16:41 +02:00