The "explain your missed clock-out" dialog (driven by hr.employee.
x_fclk_pending_reason) was set by the absence + auto-clock-out crons but only
cleared by the systray reason dialog -- never by the kiosk/NFC clock paths that
staff actually use. During the kiosk rollout the absence cron flagged the whole
company (hundreds of "absent" logs); those stale flags then nagged everyone
forever, even while currently clocked in.
Fixes:
- Clear x_fclk_pending_reason on every successful clock-in (portal, systray,
PIN kiosk, NFC kiosk). Back on the clock => no nag.
- get_status / dashboard never report pending while checked-in or exempt; the
systray also guards the dialog client-side.
- Absence detection no longer sets x_fclk_pending_reason (an absence has no
"departure time" to explain). It still logs 'absent' + notifies the office.
- One-time migration (19.0.4.2.0) clears existing stale flags.
Owner / attendance exemption:
- New "Owner" role (top of the Fusion Clock access dropdown, implies Manager)
plus a per-employee "Exempt from Attendance" checkbox.
- hr.employee._fclk_is_attendance_exempt(); the absence, auto-clock-out,
reminder and weekly-summary crons all skip exempt employees, and the dialog
is suppressed for them.
Tests: tests/test_pending_reason_exempt.py (13 cases). Full fusion_clock suite
green except pre-existing env-sensitive failures.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a tap-driven enrollment workflow so managers can pair NFC/RFID
cards to employees using a USB HID reader at their desk:
- New wizard model fusion.clock.nfc.enrollment.wizard with auto-focused
Card UID field, employee picker, and reassignment warning if the
card is already held by someone else.
- Two actions: 'Enroll Card' (single) and 'Enroll & Next' (bulk).
- Menu entry under Fusion Clock root, manager-gated.
- Exposes x_fclk_nfc_card_uid on the Employee form Clock Settings
section (next to Kiosk PIN) so it can be inspected/edited directly.
- Bumps manifest to 19.0.3.1.0 for asset cache bust.
Wizard reuses FusionClockNfcKiosk._normalize_uid so stored format
matches what the kiosk /tap endpoint looks up later. Reassignment
clears the UID from the previous holder and logs both events to the
activity log under 'card_enrollment'.