A punch is not attendance
Terminals are good at one thing. They record that user 1047 put a finger on the reader at 05:58:12. That’s a punch. It isn’t attendance yet.
Attendance is the answer to a different question: did this person work their shift, and how much of it? Getting from one to the other means pairing punches, ignoring the double tap when someone isn’t sure the reader beeped, handling the night shift that starts on Tuesday and ends on Wednesday, and applying a grace rule people actually agreed to. That translation layer is where spreadsheets get built, and it’s what we generate.
How an attendance management system works in Odoo and ERPNext
ERPNext with Frappe HR already has a solid model for this. Raw punches land as Employee Checkin records with a log type and device ID. A Shift Type defines the start and end, the grace period for late entry and early exit, and the working hours below which a day becomes half-day or absent. Auto attendance then marks Attendance records on a schedule. For device sync, there’s an open-source tool, and our guide to ERPNext biometric attendance integration walks through it. Most of our ERPNext work here is configuration plus code for the rules Shift Type can’t express.
Odoo keeps it simpler. hr.attendance stores a check-in and a check-out, the kiosk mode is in Community, and Odoo calculates overtime against working schedules. There’s no native biometric sync and no lateness rule beyond what you configure, so we add both through an addon: employee fields, a computed late value and an ir.cron job that talks to the devices.
Worked example: two shifts, three terminals and one argument about grace
Picture a distribution centre with 90 staff on two shifts, 06:00 to 14:00 and 14:00 to 22:00, and three fingerprint terminals at the gates. They run Odoo Community.
The operations manager and HR had a long debate about grace periods. Here’s where they landed. Arriving within 10 minutes of shift start is fine and counts as on time. Arriving after that is late, and the late minutes count from 06:00, not from 06:10. Their reasoning was that otherwise everyone just learns to arrive at 06:09.
So on Monday:
- Ravi punches at 06:07. Late minutes: 0.
- Maria punches at 06:14. Late minutes: 14, not 4.
- Joel punches at 05:58, then again at 05:58 because he didn’t hear the beep. The sync keeps the first punch and drops the duplicate.
The code on this page does the lateness part. Times in Odoo are stored in UTC, so the check-in is converted to the employee’s timezone before comparing. Skip that step and everyone in a UTC+4 site looks four hours early, which is flattering but useless. The device sync, duplicate filter and missing-checkout task are separate files in the same addon. Each employee carries their assigned shift start, so moving someone from mornings to afternoons is a field change, not a code change.
Before you buy more fingerprint readers
Tracking to the second. Nobody pays by the second. Round consistently, write the rounding rule down, and move on.
Geofencing office staff. For field teams, a location stamp on mobile check-in makes sense. For an office of 20, it mostly signals distrust and drains phone batteries.
Letting supervisors edit punches. Corrections should be a separate request with a reason and an approver, not a quiet edit of the raw log. Once raw punches are editable, every dispute becomes your word against theirs.
Building payroll inside attendance. Attendance should produce clean hours and late minutes. Money belongs in payroll.
Where attendance goes next
Late minutes and overtime hours are inputs, not outputs. They feed HR and payroll, and absences need to reconcile with approved time off in leave management, otherwise someone on approved leave gets marked absent. If your staff check in at customer sites, look at field service. Logistics operators running round-the-clock shifts should read our page on ERP for logistics companies.