| 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 privacy, kiosk, and audit engine every ERP Heritage attendance module stands on.
Why this module
Attendance Suite Base
Consent modelled, not assumed
Every face, fingerprint, iris, voice, photo, or geolocation capture is gated by an eh.hr.consent row with explicit pending, granted, withdrawn, and expired states. The exact consent prose shown is snapshotted onto the record at grant time, so the audit copy cannot drift if the company default text changes later.
A defensible kiosk event log
Eighteen event types (device register, heartbeat, match attempt, success, failure, geofence pass and fail, liveness, attendance in and out, consent change, exception) land in eh.hr.kiosk.event with timestamp, device, employee, confidence, and IP. Fields are read only and no write permission is granted to managers or auditors, so the trail is add only in practice.
One engine, many modules
Stable public entry points (log for audit events, raise_exception for exceptions, issue_pairing_pin for device pairing) let sibling modules plug in without coupling to each other. Install any suite module and this base is pulled in as a dependency.
Day in the life
HR captures consent on Monday and the kiosk just works.
HR opens the employee record and grants face consent. The base writes one eh.hr.consent row, snapshots the consent prose shown, and computes the expiry from the company validity setting (12 months by default). A manager creates a kiosk site for reception, clicks to issue a one shot six digit pairing PIN valid for five minutes, and the tablet trades it once for a long lived opaque token. From then on every heartbeat refreshes the device last seen, IP, and user agent, and lands an event in the audit log. Behind the curtain two daily crons run: one expires past due grants and deletes withdrawn or expired rows past the retention window, the other trims the kiosk audit trail to the configured horizon. When someone asks for a fair work audit, a manager opens the event log, filters by date, and reads. No spreadsheets, no third party cloud.
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.
The device pairing PIN is six digits, single use, and expires after five minutes. It is popped from the store on redemption and on expiry, so a captured PIN cannot be replayed. Verified by a one shot test. The PIN lives in process memory only, an acknowledged single worker limitation noted in the code.
The consent sweep and the audit sweep are two independent ir.cron records, so a failure in one does not block the other. Each pass is bounded by a batch limit and reports remaining work through ir.cron._commit_progress, so a database with years of stale rows does not freeze a worker and the framework can re trigger.
The audit and consent sweeps iterate companies and apply each company own retention horizon (consent validity, withdrawn retention, audit retention months), with a shared batch quota decremented across companies so one busy tenant cannot starve the rest in a single run.
A constraint blocks a granted consent without a grant date, a withdrawn consent without a withdrawal date, and a withdrawal date earlier than the grant date. action_grant and action_withdraw are idempotent: re running on an already granted or already withdrawn row is a no op.
All five models carry a global ir.rule scoping rows to the active companies, plus own record rules so a regular user sees only their own consent and exception rows while a manager sees the team. A consultant across tenants never sees one tenant audit trail bleed into another.
Device tokens are 32 byte secrets.token_urlsafe values, unique constrained, copy false, and read only. Rotate issues a fresh token in place and revoke deactivates the terminal so its token stops authenticating. Unknown or revoked tokens get a 401 from the kiosk endpoints.
The heartbeat endpoint rejects bursts shorter than one second per token with a 429, a soft per token cap recorded via last_seen, complementing Odoo standard route rate limiting where available.
What is inside
Built to do the job, end to end.
- Consent record (eh.hr.consent). Per employee, per type (face, fingerprint, iris, voice, photo, geolocation) consent with pending, granted, withdrawn, expired states, validity and retention windows from company settings, evidence attachment, frozen consent text snapshot, and mail thread tracking.
- Kiosk site (eh.hr.kiosk.site). A first class location model with a URL safe code unique per company, timezone, optional geofence centre and radius with coordinate validation, a device list, and a button to issue a pairing PIN.
- Kiosk terminal (eh.hr.kiosk.terminal). A registered device with a server issued rotating opaque token, last seen, last IP and user agent tracking, active flag, rotate and revoke actions, and a touch heartbeat helper called by the controller.
- Kiosk event log (eh.hr.kiosk.event). An add only audit table with eighteen event types, timestamp, device, site, employee, match confidence, IP, user agent, and a generic reference, written through a single log() entry point and trimmed by a daily cron.
- Attendance exception (eh.hr.attendance.exception). A triage record for late, early, no show, missed check out, location mismatch, low confidence, geofence violation, liveness fail, duplicate, and manual events, with severity, resolve and reopen actions, and a raise_exception() API that also writes an audit event.
- Controllers, security, config. Public kiosk pair, heartbeat, and whoami HTTP endpoints with token auth, four privilege groups (User, Manager, Admin, read only Auditor) assigned by a version branching post_init_hook, global and own record rules, two retention crons, and company level settings for thresholds and retention.
Honest about the edges
What this does not do, so nothing surprises you.
- This is a foundation engine. It ships no capture or face match UI of its own. Pair it with a kiosk modality module to actually clock employees in and out.
- The audit log is add only in practice through read only fields and an access control list that grants no write permission to managers or auditors, not through a hard write or unlink override in code. Only the Admin role can purge events, and the daily cron trims them.
- Withdrawing consent does not itself delete a biometric template. The downstream face kiosk module is responsible for resetting the enrolment flag and removing templates the next time it runs.
- The pairing PIN is held in process memory, which suits a single worker setup. Multi worker deployments retry on the worker that holds the PIN, or a later module promotes the store to a shared parameter.
- Exceptions support resolve and reopen only. There is no multi step approval chain, escalation ladder, or self approval guard in this base; those belong to higher level modules.
- Privacy mechanisms are enforced in code, but the legal and jurisdictional review of your consent text and retention periods remains yours.
Odoo 19 Community attendance base, biometric attendance consent Odoo, face attendance kiosk Odoo, kiosk device registry Odoo, attendance audit trail Odoo, hr_attendance extension, employee consent lifecycle, GDPR biometric consent record, geofence attendance Odoo, kiosk pairing PIN token, attendance exception management, multi company attendance Odoo, consent retention cron, time and attendance audit log, self hosted attendance Odoo Community
Please log in to comment on this module