This commit is contained in:
@@ -17,6 +17,11 @@ Merge those identities into a single "person" so the dashboard computes ONE
|
||||
first-badge time per human, not per badge UUID — no more false LATE warnings
|
||||
for staff who badge into multiple buildings before the cutoff. (05/28/26)
|
||||
|
||||
**Reporting:** export first badge-in times over a date range for one person or a
|
||||
multi-selected group. View an on-screen pivot (users × dates) or download a
|
||||
long-format CSV. Days with no badge-in are reported as **absent**, so it doubles
|
||||
as an attendance report. (06/19/26)
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
@@ -182,6 +187,7 @@ Per-controller actions in the modal:
|
||||
| **Refresh** | Reload the table |
|
||||
| **Sync Users** | Pull latest users from every enabled controller |
|
||||
| **🚫 Filtered** | Open the filtered-tenants modal to review and unhide |
|
||||
| **📊 Report** | Open the date-range report builder (first badge-in per day, per user, CSV export) |
|
||||
| **👥 People** | Manage merged identities and review auto-suggested merges |
|
||||
| **⚙ Controllers** | Add / manage controllers |
|
||||
| **Reset Day** | Delete all badge records for the selected date (respects the Controller filter — testing only) |
|
||||
@@ -255,6 +261,38 @@ filtered — unhiding restores their full history with no gaps.
|
||||
|
||||
---
|
||||
|
||||
## Reporting over a date range
|
||||
|
||||
The live table only shows one day. To pull first badge-in times across a range —
|
||||
for a single person or a whole group — click **📊 Report** in the header.
|
||||
|
||||
In the report modal:
|
||||
|
||||
- **Start / End** — the inclusive date range (capped at 366 days).
|
||||
- **On-time cutoff** — the HH:MM threshold for ON TIME vs LATE (defaults to the
|
||||
cutoff set in the main controls).
|
||||
- **Users** — a searchable checklist of every report subject: each merged
|
||||
**person** plus every unmerged actor. Pick one for an individual report, or
|
||||
several for a group. **Select all** and **Clear** act on the current search.
|
||||
- **Run Report** renders an on-screen **pivot**: one row per selected user, one
|
||||
column per date, each cell showing that day's first badge-in time
|
||||
(green = on time, red = late). Weekends are shaded and days with no badge-in
|
||||
show as **—**.
|
||||
- **Export CSV** downloads the same data in **long format** — one row per
|
||||
user-per-day (`Name, Date, Weekday, First In, Status, Sources`) — ideal for
|
||||
Excel or Sheets.
|
||||
|
||||
The report respects the header's **Controller** filter and **Show filtered**
|
||||
toggle, and it uses the same identity-merging logic as the live table, so a
|
||||
merged person reports **one** first-badge time per day computed across all their
|
||||
controllers. Days a selected user never badged in are reported as **ABSENT**,
|
||||
making the export a complete attendance record for the range.
|
||||
|
||||
> Reporting reads existing `badge_events` only — no schema changes, no extra
|
||||
> storage. First-badge-of-day is just `MIN(ts)` per `(person, date)`.
|
||||
|
||||
---
|
||||
|
||||
## Updating from GitHub
|
||||
|
||||
```bash
|
||||
@@ -281,6 +319,8 @@ reverse proxy with auth in front of it.
|
||||
| `POST` | `/api/unifi-access/<controller_id>` | webhook body | Receives UniFi Access webhook for that controller |
|
||||
| `POST` | `/api/unifi-access` | webhook body | Legacy alias — routes to the oldest controller |
|
||||
| `GET` | `/api/first-badge-status` | `date`, `cutoff`, `controller_id?`, `include_filtered?` | Returns first + latest badge per user (filtered tenants hidden unless `include_filtered=1`) |
|
||||
| `GET` | `/api/report/subjects` | `controller_id?`, `include_filtered?` | List selectable report subjects (merged persons + unmerged actors), each with a stable `key` |
|
||||
| `GET` | `/api/report` | `start`, `end`, `cutoff?`, `subjects?`, `controller_id?`, `include_filtered?`, `format?` | First badge-in per subject per day over the range. JSON (pivot-shaped) by default; `format=csv` returns a long-format download. Missing days reported as `ABSENT`. `subjects` is a comma-separated list of subject `key`s (empty = all) |
|
||||
| `GET` | `/api/users` | `controller_id?`, `filtered?` | List cached actors with their filtered flag |
|
||||
| `PATCH` | `/api/users/<controller_id>/<actor_id>` | `filtered` (bool) | Hide / unhide an actor from the attendance table |
|
||||
| `GET` | `/api/persons` | — | List merged people with their members |
|
||||
|
||||
Reference in New Issue
Block a user