| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Project (project)
• Discuss (mail) • Attendances (hr_attendance) • Employees (hr) |
| Community Apps Dependencies | Show |
| Lines of code | 4431 |
| Technical Name |
eh_hr_attendance_jobcost |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
| Versions | 16.0 17.0 18.0 19.0 |
Attendance Job Costing
Tag every face-kiosk punch with an analytic account, project, and task at the moment of clock-in.
Why this module
Attendance Job Costing
Cost the punch, not a memory
The job picker shows the moment a face match succeeds, so the worker tags the analytic account, project, and task while standing at the kiosk. No after-the-fact timesheet reconstruction.
Per-employee allowed lists
Each employee can carry an allowed-analytic-accounts list. The kiosk options endpoint offers only that list, so someone cannot punch into a job they are not on. Empty list means any active analytic account in the company.
Fields live on hr.attendance
Analytic account, project, and task are indexed columns on the attendance row, shown on the backend list and form. Group and filter attendance by job using standard Odoo reporting.
Day in the life
A clock-in that already knows its cost object
A field worker steps up to the face kiosk and is recognised. Because the company has require job punch on, the picker appears showing only the jobs this employee is allowed on. They tap Project Alpha, the selection POSTs to the job endpoint, and the just-created attendance row is updated with that analytic account before the welcome screen returns. Back in the office, HR opens the attendance list, adds the analytic column, and groups the day by job. The hours are already costed to the right account, with no separate timesheet entry and no end-of-week chasing.
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.
Both kiosk endpoints require a valid X-EH-Kiosk-Token mapped to an active terminal. A request without a recognised device token is rejected with 401 before any data is read or written.
The job-options endpoint refuses an employee whose company does not match the calling device, and the punch endpoint refuses an attendance row whose employee company does not match the device company, returning 404 rather than crossing companies.
When an employee has an allowed-analytic list, only the active entries in that list are offered. With no allowed list, the picker falls back to active company or shared analytic accounts, capped at 200 options.
A database constraint blocks any attendance row whose task does not belong to its selected project, so a stray task cannot be saved against the wrong job from the kiosk or the form.
The picker only interrupts when require job punch is on or more than one job is available. With a single eligible job and the toggle off, the normal success screen runs straight through, and a Skip button always lets the default job stand.
Every job punch writes a kiosk event recording the device, employee, attendance reference, and the chosen analytic, project, and task, so the selection is traceable after the fact.
What is inside
Built to do the job, end to end.
- hr.attendance fields. Indexed eh_analytic_account_id and eh_project_id Many2one fields plus an eh_task_id constrained by domain to the selected project, with an api.constrains check enforcing project membership at the database level.
- Employee configuration. eh_default_analytic_account_id and eh_default_project_id give each employee a fallback job, while eh_allowed_analytic_account_ids restricts which jobs the kiosk will offer that person.
- Company toggle. eh_hr_require_job_punch on res.company, exposed through res.config.settings inside the existing EH kiosk settings block, forces the picker even when only one job is available.
- Kiosk endpoints. A public HTTP controller exposes GET job options and POST punch job, both gated by device token, returning JSON. The punch endpoint writes the selection to the attendance row and logs a kiosk event.
- Kiosk picker script. A JS layer injected into the face kiosk shell wraps the face-match response, fetches options, renders the picker screen, posts the selection, then returns to the success and welcome flow.
- Backend views. Inherited attendance list and form views add the job-costing columns, the employee form gains a Job costing section, and the settings view adds the require-job-punch control.
Honest about the edges
What this does not do, so nothing surprises you.
- Depends on eh_hr_attendance_base, eh_hr_face_kiosk, analytic, and project. It extends the ERP Heritage face kiosk and is not a standalone attendance app.
- Stores the analytic account, project, and task on the attendance row for reporting and grouping. It does not itself post analytic ledger lines or generate project timesheets from attendance.
- The kiosk job picker is driven by a script wrapped around the face-match call in the kiosk shell. It is built for the EH face kiosk flow, not a generic Odoo kiosk.
- Allowed-job scoping is enforced in the kiosk options endpoint and the picker UI. It is guidance for the kiosk path, not a hard write-time restriction on the analytic field elsewhere.
- Targets Odoo 16 Community. There is no scheduled job, proration, or approval workflow in this module.
Odoo 16 attendance job costing, analytic account on attendance, hr_attendance analytic account, project time tracking Odoo, face kiosk job picker, per employee allowed jobs, construction time tracking Odoo, field service attendance, billable hours attendance, require job punch kiosk, attendance analytic reporting, Odoo 16 Community HR
Need this fitted to the way you work?
ERP Heritage delivers end to end Odoo work: Odoo Implementation, Customization and Development, Integration, Migration, Consultation, Support and Training. We help teams put this module into production, shape it to their process, and keep it running.
We work with businesses across Australia (Melbourne, Sydney, Brisbane, Perth, Adelaide, Canberra) and the Middle East (Dubai, Abu Dhabi, Riyadh, Jeddah, Doha, Kuwait City, Muscat). Start a conversation at erpheritage.com.au or email info@erpheritage.com.au.
Please log in to comment on this module