Skip to content

EXTRA: Reconcile facilitator affiliations against attendance (admin bulk action) - #2195

Open
maebeale wants to merge 22 commits into
mainfrom
maebeale/facilitator-affiliation-reconciliation
Open

EXTRA: Reconcile facilitator affiliations against attendance (admin bulk action)#2195
maebeale wants to merge 22 commits into
mainfrom
maebeale/facilitator-affiliation-reconciliation

Conversation

@maebeale

@maebeale maebeale commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

🤖 suggested review level: 5 Inspect 🔬 new reconciliation service + admin bulk action that creates/deactivates affiliations across an event's registrants

What is the goal of this PR and why is this important?

Facilitator affiliations are minted optimistically at registration and go Active by date alone — no-shows, cancellations, partial attendance, and never-marked registrants all silently become active facilitators.

The foundation (gating creation on training type + linking the affiliation to its registration) landed separately in #2194. This PR adds the reconciliation layer: an admin-driven step that makes affiliations match who registered and attended.

How did you approach the change?

  • ReconcileFacilitatorAffiliation (per person, org): keeps the owned facilitator affiliation active iff the person has an attended facilitator-training registration for that org; otherwise same-days it (end_date := start_date) once its source training has ended. Reactivates on a later attended. Hand-created (unowned) rows are never touched. Handles no-show-A + attended-B.
  • ReconcileEvent + "Reconcile affiliations" bulk action (under Bulk actions, facilitator trainings only): a preview-and-confirm page listing what will happen — create missing affiliations (pre-event for anyone, post-event for attendees), deactivate non-completers, reactivate late attendees — each an opt-out-able row. Records affiliations_reconciled_at; re-runnable; shows a "stale since last reconciled" nudge.
  • Created facilitator affiliation now starts on the actual training date (was first-of-month).
  • affiliations_reconciled_at column on events.

Anything else to add?

  • Deactivating the last active facilitator affiliation can flip its organization to Inactive (existing cascade, traceable via Ahoy) — accepted.
  • Full suite green (one unrelated flaky JS-confirm system spec, passes in isolation).

Copilot Bot lite review requested due to automatic review settings August 14, 2026 04:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

maebeale and others added 3 commits August 14, 2026 00:48
Groundwork for facilitator-affiliation reconciliation: an ownership FK so
reconcile only ever touches rows the registration flow created, and a
timestamp on events recording when affiliations were last reconciled.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per (person, org): keep the owned facilitator affiliation active iff they have
an attended facilitator-training registration for that org; otherwise same-day
it (end_date := start_date). Hand-created rows are left alone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A preview-and-confirm page (under Bulk actions on facilitator trainings) that
same-days the owned facilitator affiliation of anyone who didn't complete the
training, keeps/reactivates completers, and records when it last ran. Admins can
opt individual rows out before applying.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maebeale
maebeale force-pushed the maebeale/facilitator-affiliation-reconciliation branch from 68913c9 to e765a96 Compare August 14, 2026 04:58
Copilot Bot review requested due to automatic review settings August 14, 2026 04:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@maebeale maebeale changed the title Reconcile facilitator affiliations against attendance Reconcile facilitator affiliations against attendance (admin bulk action) Aug 14, 2026
@maebeale
maebeale marked this pull request as ready for review August 14, 2026 05:11
…ations on reconcile

Start the created facilitator affiliation on the actual training date rather than
the first of its month. Extend the Reconcile affiliations action to also create
missing facilitator affiliations (pre-event for anyone, post-event for attendees),
shown as opt-out-able 'Will be created' rows alongside the deactivations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 05:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.


def facilitator_start_date
(@training_date || Date.current).to_date.beginning_of_month
(@training_date || Date.current).to_date

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Intentional shift toward accurate dates: this starts the facilitator affiliation on the actual training date rather than the first of its month (changing code that just landed in #2194). Reconciliation works either way; flagging since it edits a freshly-merged file.

maebeale and others added 6 commits August 14, 2026 07:49
On a non-training event, the Reconcile affiliations action now deletes
facilitator affiliations that were auto-created off it (job affiliations are
left alone), shown as opt-out-able 'Will be deleted' rows. Same-day rows also
gain a per-row 'Delete instead' checkbox. The action is now available on every
event, not just trainings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e status

Preview now lists every registrant-org pair, grouped by action, and adds a
'Not reconciled' section explaining why each is left alone, with attendance
status shown per row.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ttendance

Preview now groups actionable rows by person with the shared editable attendance
chip and a note of their other-org facilitator affiliations; each facilitator
affiliation is an individual row showing its date range with an Edit link to the
person page. 'Not reconciled' is a collapsible section grouped by reason
(hand-entered last), each reason collapsible too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render the shared attendance chip (not plain text) in the Not reconciled rows so
status is editable there too, move the Edit link ahead of the status, and shorten
the affiliation date range to 'Oct 13, 2026 – present'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion controls

Reconcile every facilitator affiliation for a linked org (not just app-created),
gated to post-event so a pre-event run never deactivates and with per-row opt-out.
Move the include checkbox into the action chip so it's clear checking it performs
that action, move the other-org facilitator note below the rows, link org/dates to
the specific affiliation anchor and names to the registration, and strengthen the
Not reconciled section headers (open by default, expand/collapse all).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eader note

Style the include/delete-instead controls as buttons that only turn error-red when
selected (peer-checked, no JS); add hover tooltips explaining deactivate/delete
(delete as bullets: this affiliation only, job + other-org affiliations untouched).
Move the 'Also a facilitator at …' note beside the name, truncated and linking to
the single affiliation anchor (or the affiliations section when several). Order the
Not reconciled sections with 'Active — attended' second-to-last.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 12:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…sections

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 12:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…exclusive

Move the checkbox back inside each button (has-[:checked] colors the whole button
on select, error-red for deactivate/delete). Add an exclusive-checkboxes Stimulus
controller so checking 'Delete instead' clears 'Will be deactivated' and vice versa;
apply now treats a delete key as delete regardless of the include key.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 13:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

'Preview changes' now posts to a confirmation screen that shows exactly which
affiliations get created/reactivated/deactivated/deleted (actioned rows only),
with Go back to edit (selections restored) or Perform changes. Add per-row
instructions under the action buttons and a header row with a warning that checked
boxes change affiliations. New exclusive-checkboxes controller registered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 13:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

maebeale and others added 5 commits August 14, 2026 09:25
Thread return_to through the attendance status badge and add a reconcile case to
EventRegistrations#update so toggling attendance from the reconcile page reloads it
(with fresh attendance) and a success flash, instead of jumping to the roster.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Stimulus manifest is explicit, so the new exclusive-checkboxes controller was
never loaded — register it and use an explicit change event so Delete instead and
Will be deactivated actually clear each other. Reword the deactivate row note to
spell out the two options (mark Attended = permanent, uncheck = one-time).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… note says 'both boxes'

Turbo ignores a 200 HTML render on a form POST (only 4xx/5xx render), so the
confirmation screen never showed. Submit the preview form with turbo disabled.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 13:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…on attendance toggle

Replace the deactivate/delete checkboxes with a radio group per row
(Deactivate/Delete/Keep active, and action/keep for the others), styled as the same
buttons via has-[:checked]. Radios are natively mutually exclusive, so remove the
exclusive-checkboxes Stimulus controller and the per-row instruction note.

Fix the real reason 'Preview changes' did nothing: the attendance chip's form was
nested inside the reconcile form (invalid HTML), so the submit/inputs fell outside
it. Render the reconcile form standalone and join the radios/submit via the HTML
form= attribute. Switch the params to an outcome map { row.key => choice }.

Toggling attendance now scrolls back to that item's anchor, not the top.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 13:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 14:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@maebeale maebeale changed the title Reconcile facilitator affiliations against attendance (admin bulk action) MAYBE: Reconcile facilitator affiliations against attendance (admin bulk action) Aug 14, 2026
@maebeale maebeale changed the title MAYBE: Reconcile facilitator affiliations against attendance (admin bulk action) EXTRA: Reconcile facilitator affiliations against attendance (admin bulk action) Aug 14, 2026
… labels

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 17:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot Bot review requested due to automatic review settings August 14, 2026 23:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

2 participants