Attendance Migration for Odoo 18
Move your people and their punch history off any biometric or punch-clock system into Odoo 18, from plain CSV, with a dry run before anything is written.
Why this module
Attendance Migration for Odoo 18
Dry run before you commit
Every import defaults to dry run. The wizard reports exactly what it would create, update, or skip, row by row, and writes nothing to the database. You read the result, fix the source CSV, and only then run it for real.
Any system that exports CSV
The column mapping is fixed and documented on the wizard, so the operator does not need a per-vendor adapter and there is no live link to the old system. If the incumbent biometric or punch-clock platform can produce a CSV, it can feed this importer.
It tells you what it will not do
Face templates do not migrate because recognition models produce incompatible embeddings, so re-enrolment is required. Prior consent is not imported by design. The module states these limits up front rather than discovering them mid-cutover.
Day in the life
An HR admin cuts over from an old punch-clock system in an afternoon.
They export the staff list and the last year of punches as two CSV files. In the employee wizard they leave dry run on, upload the staff file, and read the preview: forty rows would be created, eight matched by work email would be updated, two skipped. They correct a duplicate name in the source, run it live, and the result log confirms every row. Then the attendance wizard: matched by email first and name as fallback, with skip unknown employees on so a few orphan rows are logged and set aside rather than aborting the run. A check-out that lands before its check-in is caught and reported as an error, not written. One open attendance with no check-out comes across as an open record. The whole cutover is two wizards and two result logs, with re-import available any time the source needs a fix.
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.
Dry run is the default on both wizards. It walks every row, resolves the employee, builds the write values, and logs what it would do, but the create and write calls are skipped entirely. Nothing reaches the database until you turn dry run off.
Each row is processed inside its own try and except. A bad row, an unparseable date, an empty name, raises an error that is counted and written to the log, while every other row in the file still imports. One malformed line does not abort the run.
In update mode the employee importer only writes non-empty CSV values, so a partial source file updating a job title cannot blow away an existing email or department with blanks. Empty cells are left untouched on the matched record.
Attendance rows whose employee cannot be matched are either logged and skipped (skip unknown employees on) or made to abort the row as an error (off), so you choose between a forgiving import and a strict one that surfaces every gap.
A check-out that is not strictly after its check-in is rejected as an error for that row and no attendance is created, so reversed or duplicated timestamps from the old system do not become impossible records.
A default kiosk site is resolved by code within the current company only, and an unrecognised site code is ignored rather than blocking the import, so the row still creates the employee and just leaves the default site unset.
Both wizards match case-insensitively, email first then full name as a fallback, using exact ilike comparison rather than fuzzy matching, so a renamed employee is still found by their work email and accidental partial matches are avoided.
Missing required columns (check_in, or name, or any employee match key) and undecodable bytes raise a clear up-front error naming the columns found and the encoding tried, so a malformed export fails loudly before any row is touched.
What is inside
Built to do the job, end to end.
- Employee CSV importer. A wizard that reads a CSV of staff and matches existing hr.employee rows by work email or full name, creates rows that do not exist, and maps name, work email, job title, department (created if missing), an optional kiosk PIN, and a default kiosk site resolved by code in the current company. A default analytic account is set only when the optional jobcost field is present.
- Attendance history importer. A second wizard that reads a CSV of punches, matches each row to an employee by email then name, and creates hr.attendance records with check-in and check-out timestamps. Empty check-out is allowed as an open record. Optional analytic and project per row are wired only when those fields exist on hr.attendance.
- Configurable parsing. Both wizards expose encoding (UTF-8, UTF-8 with BOM, Latin-1), delimiter (comma, semicolon, tab), and a documented column reference on the form. Datetimes are parsed across six common formats including ISO with a space or a T separator and day-first dates.
- Result log and counts. Every run, dry or live, writes a summary line and a per-row log into a read-only result field, with separate counters for created, updated, skipped, and error rows, so the operator can correct the source CSV and re-import.
- Admin-scoped access. Both wizard models are reachable only through an admin-gated Migration menu under the attendance configuration, with create and write granted to the HR admin and manager roles defined in eh_hr_attendance_base.
Honest about the edges
What this does not do, so nothing surprises you.
- This is a one-time switching tool, not a connector. There is no live API integration with the incumbent system and no scheduled sync; you import from exported CSV files.
- Face recognition templates do not migrate. Different recognition models produce incompatible embeddings, so employees must re-enrol at the new system. Plan for re-enrolment.
- Prior consent is not imported by design. Consent must be granted fresh at the new system after the employee reads the new privacy notice; the module does not accept claimed prior consent.
- Column mapping is fixed and documented on each wizard rather than freely remappable in the UI; your source CSV must use, or be renamed to, the recognised headers.
- Employee matching is exact and case-insensitive on email then name, not fuzzy. Inconsistent spellings between systems will not auto-match and will create new rows unless reconciled first.
- Department is the only related record auto-created on import. Job title and kiosk site must already resolve; analytic, project, and the default analytic account map only when those optional fields are installed.
- Requires eh_hr_attendance_base and the standard hr_attendance module. It targets Odoo 18 Community.
attendance migration odoo 18, hr_attendance csv import, employee csv import odoo, biometric attendance switch, punch clock data migration, time and attendance migration, kiosk pin import, attendance history importer, odoo 18 community hr, dry run csv import
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.
Languages
Available in 19 languages
The interface ships translated out of the box. Switch language in Odoo and the fields, menus, and messages follow.
Modules teams pair with this one.
Premium ERP Heritage modules that extend the same stack, each built to the same engineering bar.
Shared foundation for the ERP Heritage Employment Hero country packs
Bring Employment Hero onboarding workflows, employee goals and contractor flags into Odoo Community as real recor...
End to end French B2B and B2G electronic invoicing for the DGFiP reform, generating Factur-X PDF/A-3 with embedde...
Accept ZainCash wallet payments in Iraq at your Odoo checkout, on the ZainCash Payment Gateway v2 with OAuth2, re...
Sync Employment Hero ATS recruitment job openings into the standard Odoo Recruitment app, mapping each opening on...
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Attendances (hr_attendance)
• Discuss (mail) • Employees (hr) |
| Community Apps Dependencies | Show |
| Lines of code | 1991 |
| Technical Name |
eh_hr_attendance_migrate |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
Please log in to comment on this module