| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Attendances (hr_attendance)
• Discuss (mail) • Employees (hr) |
| Community Apps Dependencies | Show |
| Lines of code | 1964 |
| Technical Name |
eh_hr_attendance_migrate |
| 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 | 1964 |
| Technical Name |
eh_hr_attendance_migrate |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
| Versions | 16.0 17.0 18.0 19.0 |
Attendance Migration
Two CSV importers that carry your employee master and attendance history off any incumbent time clock, with a dry run before every commit and a per row error log.
Why this module
Attendance Migration
Dry run before you ever write
Both wizards open with dry run ticked. You see the would create, would update, and would skip lines for every row, with zero database writes, then untick to commit. The result header reads DRY RUN or COMMITTED so you can never confuse a preview for a run. Verified by tests that assert nothing is created in dry mode.
One bad row never sinks the import
Each row is processed in its own try block. A missing name, an unparseable date, a check out before check in, or an unknown employee is counted as an error or a skip and logged with its row number, while every good row around it still lands. Fix the source line, re run, repeat.
No connector, no lock in
LGPL-3 source on disk. No live API to the old system, no per vendor adapter to license, no activation key, no phone home. The CSV your previous system already knows how to export is the only interface. Read the wizard code, extend it, keep it.
Day in the life
Export. Dry run. Read the log. Commit. Last quarter is live in Odoo before lunch.
The implementer exports two CSVs from the previous time and attendance system, an employees file with names, emails, job titles, kiosk PINs and site codes, and an attendance history file with check in and check out times. They open the employee importer, attach the file, set encoding and delimiter to match the export, choose match by email then name, and leave dry run ticked. The log reports 312 would update, 4 would create, 1 skipped for a missing name. They correct that one line in the source, untick dry run, and run again. Same pass for attendance history, where unknown employees are skipped and logged rather than aborting the batch. By late morning the new database knows who everyone is and what they did last quarter, and the only thing left for cutover day is fresh face enrolment.
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.
Update mode writes only non empty CSV values, so importing a file that is missing a column never blanks the job title or email you already have in Odoo.
An attendance row whose check out is not strictly after its check in is rejected as a row level error and never written, so you do not import a negative shift.
Six datetime layouts are accepted, including space and ISO T separators, with and without seconds, and day first formats, so most exports parse without a pre conversion step.
A default kiosk site is resolved by its code within the active company only, so a code that exists in another company will not silently cross wire an employee.
You choose whether an unmatched employee is logged and skipped so the batch continues, or treated strictly so the run flags it, rather than the importer guessing for you.
A department named in the employee CSV that does not yet exist is created during import, so org structure arrives with the people rather than as separate prep work.
What is inside
Built to do the job, end to end.
- Employee master importer. Transient wizard eh.hr.migrate.employee. Matches hr.employee by full name, work email, or email then name (selectable). Creates missing rows, and in update mode fills matched rows from non empty values. Sets job title, a fallback kiosk PIN, a default kiosk site by code within the active company, a department created if new, and a default analytic account when that field exists on the employee model.
- Attendance history importer. Transient wizard eh.hr.migrate.attendance. Matches employees by email then name, parses six datetime formats, validates that check out follows check in, and creates hr.attendance rows. When the job costing fields are installed it resolves an analytic account and a project by name and attaches them. Unknown employees are skipped or strict per your choice.
- Dry run and the result log. Both wizards default to dry run on. Dry mode writes nothing and previews every row. Every run returns a Text result that opens with DRY RUN or COMMITTED, then created, updated, skipped, and error counts, then a numbered line for each row including the exact reason any row failed. Fix the source, re run.
- Configurable read, fixed schema. Pick the file encoding (UTF-8, UTF-8 with BOM, or Latin-1) and the delimiter (comma, semicolon, or tab) to match your export. Headers are recognised by name, case insensitive, with spaces and dashes normalised. A built in column reference on each wizard lists exactly which headers each importer reads.
- Access and placement. Both wizards live under the attendance configuration menu and are restricted to the HR admin and HR manager groups by access rules. Depends on eh_hr_attendance_base and the standard hr_attendance module. Sixteen automated tests cover dry run, commit, matching, skip and strict modes, date parsing, and per row error isolation.
Honest about the edges
What this does not do, so nothing surprises you.
- Not a live connector. There is no API link to the previous system. You export a CSV from it and the wizard reads that file. If the old system cannot export tabular data, this tool cannot help.
- Headers follow a fixed recognised schema per importer, not a free column mapping UI. You name your CSV columns to match the documented headers (case, spaces, and dashes are normalised); there is no per column remap screen.
- Encoding choices are UTF-8, UTF-8 with BOM, and Latin-1 only. Other encodings such as CP1252 or UTF-16 must be converted to one of these once before import.
- The attendance importer does not deduplicate. Re running a committed attendance file creates a second set of hr.attendance rows for the same shifts, so commit each history file once and use dry run to confirm before you do.
- Face recognition templates do not migrate. Different models produce incompatible embeddings, so every face must be re enrolled at the new system. Plan a cutover window for it.
- Consent is not carried over. It is granted fresh at the new system after the employee reads the new privacy notice. The importer never imports a claimed prior consent flag.
- Analytic account, project, and the default analytic on the employee are populated only when those fields are present, which depends on the optional job costing module being installed.
attendance migration odoo, hr_attendance csv import, employee csv import odoo 19, time and attendance migration, biometric attendance switchover, punch clock data migration, time clock history import, odoo 19 community attendance importer, dry run csv import, per row error log import, import attendance history odoo, vendor neutral attendance import, switching biometric attendance system, hr employee bulk import csv, kiosk site code import
Please log in to comment on this module