先说结论
Odoo Attendance 不是一个“打个卡、算个时长”的轻量工具。
从源码看,它至少同时在做四件事:
- 保证同一员工的考勤切片不重叠
- 保证不会出现多个未签退的开放记录
- 在必要时自动签退
- 对缺勤天补技术性 attendance,用于后续加班/欠工时计算
所以它真正管理的不是按钮动作,而是:
员工出勤事实能不能被系统稳定计算。
为什么 Odoo 要严查“开放考勤”
源码里 _check_validity() 很严格。
它会检查同一员工:
- 最多只能有一条未
check_out的开放考勤 - 新记录不能与已有记录时间重叠
这看起来像小题大做,实际非常必要。
因为一旦允许:
- 同时存在两条开放记录
- 或多条时间交叉记录
后面的:
- worked hours
- overtime
- 出勤分析
- 与排班对比
都会直接失真。
所以 Attendance 的第一原则不是“尽量放过用户”,而是先保时间切片干净。
worked hours 为什么不是简单的 check_out - check_in
源码里的 _get_worked_hours_in_range() 说明,Odoo 还会考虑:
- 员工/日历时区
- 对应 resource calendar
- 是否是 flexible 工时
- 午休区间是否应被扣除
这意味着系统想表达的不是“表面经过了几小时”,而是更接近:
在这个制度下,可计为工作时长的部分是多少。
所以同样 9:00 到 18:00,两家公司的 worked hours 可能并不完全同义。
自动签退到底不是为了省点一下按钮
源码里的自动签退逻辑,会去看:
- 公司是否开启
auto_check_out - 员工日历是否不是 flexible
- 当天已累计工作时长
- 日历理论工时
- 容差
auto_check_out_tolerance
如果员工超过理论工作时长太多,系统就会自动补 check_out,并记录消息说明这是自动签退。
这说明自动签退的真正目的不是“替员工补操作”,而是:
防止一条忘记签退的开放记录无限增长,污染当天乃至后续计算。
它首先是在保护数据质量,其次才是便利性。
为什么还要有“技术性缺勤”
很多人第一次看到 _cron_absence_detection() 会很惊讶:
员工昨天根本没打卡,系统为什么还要创建一条 attendance?
因为这里创建的是技术性 attendance,不是在伪造真实出勤,而是在补一个“可被计算的缺勤占位”。
源码会针对:
- 开启 absence management 的公司
- 非弹性工时员工
- 已处于合同内的员工
- 昨天没有任何 overtime line 记录的员工
生成一条极短的 technical attendance。
目的很明确:
让系统能在加班/欠工时规则里识别这一天是“无正当出勤”的。
为什么 Attendance 会联动 overtime,而不是只管出勤
源码在 create() / write() 后会调用 _update_overtime()。
而 _update_overtime() 又会结合:
- 员工版本区间
- 对应规则集
ruleset - 排班区间
- 考勤日期集合
来生成 overtime lines。
这意味着考勤记录不是终点,而是后续时间规则计算的原料。
所以前面那些严格校验——开放记录、防重叠、自动签退、技术性缺勤——都是在给后续计算打地基。
这对业务理解有什么帮助
1. Attendance 管的是“事实切片”,不是纯界面操作
按钮只是入口,真正重要的是时间片段是否干净。
2. 自动签退是数据治理机制
不是偷懒功能。
3. 技术性缺勤不是造假
它是在把“没来上班”也编码成可运算事实。
一句话记忆
Odoo Attendance 管的不是“员工点了几次按钮”,而是可被后续规则可靠计算的出勤时间事实。
DISCUSSION
评论区