| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Attendances (hr_attendance)
• Discuss (mail) • Employees (hr) |
| Community Apps Dependencies | Show |
| Lines of code | 1510 |
| Technical Name |
eh_hr_attendance_base |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
| Versions | 16.0 17.0 18.0 19.0 |
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Attendances (hr_attendance)
• Discuss (mail) • Employees (hr) |
| Community Apps Dependencies | Show |
| Lines of code | 1510 |
| Technical Name |
eh_hr_attendance_base |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
| Versions | 16.0 17.0 18.0 19.0 |
Attendance Suite Base
The shared consent, kiosk, and audit engine every ERP Heritage attendance module builds on.
Why this module
Attendance Suite Base
Capture is gated on explicit consent
Every face, fingerprint, iris, voice, photo, or geolocation capture is anchored to an eh.hr.consent record with pending, granted, withdrawn, and expired states. The exact consent prose shown is snapshotted onto the record at grant time, so the audit trail cannot drift if the company default text changes later.
An audit log managers can read but not edit
Every kiosk event lands in a timestamped audit row with device, employee, match confidence, and IP. The fields are readonly and no group has write access, so the trail stands up as evidence in a fair work or labour dispute rather than being something staff can quietly alter.
One registry, many capture modules share it
Site model, device registry, audit log, and exception API are owned here so the face kiosk, reporting, geofence, and roster modules all write to the same surface. The public raise_exception and log entry points give any module one consistent way to record events.
Day in the life
From kiosk pairing to a clean audit trail
An admin opens a kiosk site, clicks Pair a new device, and reads the one-time six-digit PIN to the operator at the terminal. The kiosk POSTs the site code and PIN and receives a long-lived device token; the pairing is logged. From then on the device heartbeats with its token, the server records last-seen, IP, and user agent, and returns the site geofence and match threshold. When a capture module raises a late, no-show, or low-confidence event it calls raise_exception, which files an exception row and an audit event in one step. Overnight, two independent crons expire stale consents, purge withdrawn records past their retention window, and trim the audit log to each company's configured horizon, all batched so a busy install never stalls a worker.
Edge cases
The cases most modules quietly ignore.
In the shipped code today, each one a place where a cheaper module silently does the wrong thing.
Grant and withdraw short-circuit if the consent is already in that state, and exception resolve and reopen no-op when already resolved or open, so repeated clicks or replayed calls never double-stamp dates.
The consent and audit sweeps run as two separate daily crons so a failure in one cannot block the other. Each is bounded by a batch limit and reports remaining work through ir.cron._commit_progress so the framework re-triggers instead of one worker grinding through years of stale rows.
Both sweeps loop company by company, reading each company's own validity, consent-retention, and audit-retention horizons, so a multi-company database applies the correct window to each tenant rather than a single global cutoff.
Pairing PINs are single-use and expire after five minutes. A used PIN is dropped immediately, a PIN that does not match the requested site code is rejected, and an unknown or inactive site returns a not-found rather than issuing a token.
Heartbeat and whoami require the device token header and return 401 for a revoked or unknown token. Bursts shorter than one second are rejected with 429, and a revoked device deactivates rather than deleting, preserving its audit history.
Audit event fields are readonly with no write access for any group, and the consent prose is snapshotted onto each consent record at grant time so later edits to the company default never rewrite history.
Global record rules scope every model to the user's active companies, while a regular attendance user can read only their own consent and exception rows. The auditor role is read-only and deliberately does not imply the user role, and the kiosk fallback PIN field is restricted to managers.
What is inside
Built to do the job, end to end.
- Consent lifecycle and config. eh.hr.consent with six capture types, four states, evidence storage, and a frozen consent-text snapshot. Grant computes the expiry from the company validity setting; date constraints reject a withdrawal dated before its grant. Company settings cover consent validity, consent and audit retention months, default face consent text, match threshold, and kiosk idle reset, all exposed in Settings.
- Kiosk sites and device registry. eh.hr.kiosk.site with URL-safe code unique per company, timezone, and optional geofence with validated latitude, longitude, and radius. eh.hr.kiosk.terminal issues a server-side opaque token with rotate and revoke actions, tracks registered-on, last-seen, last IP, and user agent, and links back to its site and company.
- Pairing and heartbeat controller. Public HTTP endpoints for pair, heartbeat, and whoami. Pairing trades a one-time five-minute PIN for a device token; heartbeat and whoami authenticate by token header, refresh last-seen, and return site config including geofence and match threshold. A soft one-second cap guards against heartbeat bursts.
- Exceptions and audit trail. eh.hr.attendance.exception with ten typed reasons, three severities, and resolve and reopen workflow. A public raise_exception API files the row and an audit event together. eh.hr.kiosk.event is an append-only log with eighteen event types and a single log entry point used across the suite.
- Security model and crons. Four privilege groups, user, manager, admin, and read-only auditor, with global per-company record rules and own-row rules for regular users. Two daily retention crons run under the root user, each batched and progress-reporting. A version-aware post-init hook files the groups under one access dropdown.
Honest about the edges
What this does not do, so nothing surprises you.
- This is a foundation module. It ships the consent, site, device, exception, and audit models plus the pairing and heartbeat endpoints, but it does not itself perform face capture, matching, attendance posting, or reporting. Those live in the capture and reporting modules that depend on it.
- Consent withdrawal sets the consent state and date and is available to managers, but this base module does not itself delete or reset any stored biometric template; that cascade belongs to the capture module that owns the template.
- Pairing PINs are held in an in-process memory cache, which suits a single-worker setup or admin-and-operator pairing on the same worker. Multi-worker deployments may need to retry pairing on the worker that issued the PIN.
- Geofence coordinates and radius are validated and returned to the kiosk, but enforcement of the fence at clock-in time is the responsibility of the capture or mobile module that consumes them.
- Requires the eh_hr_compat helper and depends on hr and hr_attendance. It targets Odoo 16 Community and is not a standalone end-user attendance app on its own.
Odoo 16 attendance, biometric consent management, face attendance kiosk, kiosk device registry, attendance exception log, kiosk audit trail, time and attendance Odoo, employee clock in clock out, GDPR biometric consent, multi-company HR attendance, geofence attendance, hr_attendance extension, consent retention policy, kiosk pairing token, Odoo Community HR
Please log in to comment on this module